[cfe-dev] JIT doens't resolve address - Resolve obj-Addresses?

via cfe-dev cfe-dev at lists.llvm.org
Wed May 10 07:10:58 PDT 2017


Hello Lang,

thank you very much! Now I'm understanding the whole JIT-ting a lot 
better. I guess, that every problem I had is solved now. Thank you!

Kind regards
Jörn



From:   Lang Hames <lhames at gmail.com>
To:     bjoern.gaier at horiba.com
Cc:     Clang Dev <cfe-dev at lists.llvm.org>, LLVM Developers Mailing List 
<llvm-dev at lists.llvm.org>
Date:   10.05.2017 00:50
Subject:        Re: [cfe-dev] JIT doens't resolve address - Resolve 
obj-Addresses?



Hi Björn,

But I don't know what to do with "NotifyObjectLoaded". So I overloaded the 
function and can now access the sections. Soo... I allocate memory in my 
sharedmemory for the sections and use mapSectionAddress to change the 
addresses. But how do I copy the memory in the finalizeMemory method? I 
don't have access to the section anymore! 

You're following the recipe for "the hard way", so I'll stick to that: 
Notice that in this scheme the each section is allocated twice. The first 
allocation is done by allocateCodeSection/allocateDataSection, and you 
have to store a pointer to the memory you allocate (and the section size, 
alignment, memory protections, etc) in a collection somewhere inside the 
allocator. The second allocation should be done in NotifyObjectLoaded: You 
use the stored section information (sizes and alignments) to allocate the 
sections at their final addresses inside shared memory, then use the 
stored local addresses and newly allocated final addresses to set up the 
address mapping. Finally, in finalizeMemory, you copy the relocated bytes 
from the local memory allocated by the first allocation to the shared 
memory allocated by the second one, then set the appropriate memory 
protections on the shared memory. The pseudo-C++ for the whole process 
looks like this:

RTDyldLinkingLayer::loadObject(Obj) {
  for (auto &Section : Obj.sections()) {
    uint8_t *LocalAddr = MemMgr.allocateSection(Section.Size, 
Section.Align, ...);
    copyToLocalMemory(LocalAddr, Section);
  }
  MemMgr.notifyLoaded(Obj);

  // RTDyldLinkingLayer::finalize() will be called implicitly when you try 
to take the address
  // of a symbol.
}

RTDyldLinkingLayer::finalize() {
  // Apply relocations to our local copy of the sections based on the 
final addresses set up
  // in the address mapping.
  applyRelocationsToLocalMemory();

  // Call the memory manager to copy the now-relocated bytes from local 
memory to their final
  // addresses, then mprotect the memory so that the code at the final 
address can be
  // executed.
  MemMgr.finalizeMemory();
}

uint8_t* MyMemoryManager::allocate*Section(Size, Align, ...) {
  uint8_t *LocalAddr = allocate_aligned_memory(Size, Align);
  AllocsToRemap.push_back(RemapRecord(LocalAddr, Size, Align));
  return LocalAddr;
}

void MyMemoryManager::notifyLoaded(Obj, RTDyld) {
  for (auto &AR : AllocsToRemap) {
    JITTargetAddress FinalAddr = allocateSharedMemory(AR.Size, AR.Align);
    RTDyld.mapSectionAddress(AR.LocalAddr, FinalAddr);
    AllocsToFinalize.push_back(FinalizeRecord(LocalAddr, FinalAddr, 
Size));
  }
  AllocsToRemap.clear();
}

void MyMemoryManager::finalizeMemory() {
  for (auto &AR : AllocsToFinalize) {
    copyFromLocalToFinalMemory(AR.FinalAddr, AR.LocalAddr, AR.Size);
    setMemoryProtections(AR.FinalAddr, Size);
  }
  AllocsToFinalize.clear();
}

Hope this helps!
 
If you're JITing across processes with ORC it might be worth looking at 
OrcRemoteTargetClient.h and OrcRemoteTargetServer.h: They provide a 
built-in remote memory manager that can allocate memory in the JIT target 
process and convey those allocations back to the JIT compiler via RPC. 
There's an example of this in the 5th entry of the Building A JIT tutorial 
- http://releases.llvm.org/4.0.0/docs/tutorial/BuildingAJIT5.html (though 
unfortunately I haven't had time to write the tutorial text for it yet).

Cheers,
Lang.


On Tue, May 9, 2017 at 7:24 AM, <bjoern.gaier at horiba.com> wrote:
Hello Lang, 

thanks for your answer! With small steps I'm coming to my goal. 

But I don't know what to do with "NotifyObjectLoaded". So I overloaded the 
function and can now access the sections. Soo... I allocate memory in my 
sharedmemory for the sections and use mapSectionAddress to change the 
addresses. But how do I copy the memory in the finalizeMemory method? I 
don't have access to the section anymore! 
Plus, is there a way to reallocate global variables too, which aren't 
declared as extern - give them another memory location? I see these values 
with "symbols" in "NotifyObjectLoaded", but I don't have an address for 
them. 
And... can I load .obj files, which Visual Studio had generated? 

Kind regards 
Björn 



From:        Lang Hames <lhames at gmail.com> 
To:        bjoern.gaier at horiba.com, Clang Dev <cfe-dev at lists.llvm.org>, 
LLVM Developers Mailing List <llvm-dev at lists.llvm.org> 
Date:        07.05.2017 04:37 
Subject:        Re: [cfe-dev] JIT doens't resolve address - Resolve 
obj-Addresses? 



Hi Bjoern, 

CCing cfg-dev (since that's where the conversation started) and llvm-dev 
(since it's relevant there). 

Do you know if there is a way to obtain the fully resolved obj-code? I 
wanted to load the functions into a shared memory, but how? The only thing 
I receive is a function pointer, but I don't know how large the function 
'behind' is. Even a call to _msize (windows) does only resolve in a 
crash.  

You can access the fully-resolved object code on a per-section basis 
(there is no easy way to do it per-function) by using a custom memory 
manager, rather than SectionMemoryManager. 

There are two ways to go about this: 

(1) The easy way (only valid for shared-memory on the same machine) is to 
allocate the sections directly out of shared memory (by overriding 
allocateCodeSection/allocateDataSection). 

(2) The hard way (which is general enough to allow you to copy the 
relocated bytes to remote machines) is three part: 
(a) Allocate the sections locally (e.g. using malloc, or inheriting from 
SectionMemoryManager and capturing the allocation details) 
(b) Override the notifyObjectLoaded method to allocate the final memory 
locations, then call RTDyldMemoryManager::mapSectionAddress to map each 
local allocation to its corresponding final address 
(c) Override finalizeMemory to copy the relocated bytes to their final 
addresses 

Hope this helps. 

Cheers, 
Lang. 




On Tue, May 2, 2017 at 10:47 PM, <bjoern.gaier at horiba.com> wrote: 
Hello Lang, 

your answer explained a lot to me, thank you for that. Do you know if 
there is a way to obtain the fully resolved obj-code? I wanted to load the 
functions into a shared memory, but how? The only thing I receive is a 
function pointer, but I don't know how large the function 'behind' is. 
Even a call to _msize (windows) does only resolve in a crash. 

Kind regards 
Björn 



From:        Lang Hames <lhames at gmail.com> 
To:        bjoern.gaier at horiba.com 
Cc:        willdtz at gmail.com, Clang Dev <cfe-dev at lists.llvm.org> 
Date:        01.05.2017 20:15 
Subject:        Re: [cfe-dev] JIT doens't resolve address - Resolve 
obj-Addresses? 




Hi Björn, 

I tried using your code and now it works! I'm happy and surprised! 

Oh - I missed that Will's code had fixed your issue. That's great. :) 

Do you know if there is a way to directly load .obj-Files and resolve the 
references with own addresses? Like when somebody used printf in the 
generated obj-File, but I replace the address with my own printf?  

You can load precompiled object files by calling addObjectSet on the 
ObjectLayer. 

All external symbol references are resolved by the JITSymbolResolver that 
is created by createLambdaResolver. In your example the resolution process 
is two-step: First the JIT searches its own function definitions to see if 
there is a function called "printf" defined there (this is what the call 
to CompileLayer.findSymbol does): 

[&](const std::string &Name)  { 
  printf("FLUSH :0\n"); 
  if (auto Sym = CompileLayer.findSymbol(Name, false)) 
    return Sym; 
  return JITSymbol(nullptr); 
} 

Then, if it doesn't find a definition there, it falls back to searching in 
the current process (this is what 
RTDyldMemoryManager::getSymbolAddressInProcess does): 

[](const std::string &S)  {  
  printf("PLUSH :0\n");  
  if (auto SymAddr =  
        RTDyldMemoryManager::getSymbolAddressInProcess(S))  
    return JITSymbol(SymAddr, JITSymbolFlags::Exported);  
  return JITSymbol(nullptr);  
} 

If, for example, you wanted to redirect calls to printf to your own custom 
version (while resolving all other externals by the normal process) you 
could change the second lambda like so: 

[](const std::string &S)  {  
  printf("PLUSH :0\n"); 
  if (S == mangleName("printf")) 
    return JITSymbol((JITSymbolAddress)&myCustomPrintf, 
                     JITSymbolFlags::Exported); 
  if (auto SymAddr =  
        RTDyldMemoryManager::getSymbolAddressInProcess(S))  
    return JITSymbol(SymAddr, JITSymbolFlags::Exported);  
  return JITSymbol(nullptr);  
} 

(You'll just have to pull the mangling logic from findSymbol out into its 
own "mangleName" function for this). 

Hope this helps. 

Cheers, 
Lang. 


On Sun, Apr 23, 2017 at 11:08 PM, <bjoern.gaier at horiba.com> wrote: 
Hello Mr. Dietz, 

I tried using your code and now it works! I'm happy and surprised! I will 
now compare the codes and try to spot the main difference! Thanks for your 
help! 
Do you know if there is a way to directly load .obj-Files and resolve the 
references with own addresses? Like when somebody used printf in the 
generated obj-File, but I replace the address with my own printf? 

Kind regards 
Björn 



From:        Will Dietz <willdtz at gmail.com> 
To:        bjoern.gaier at horiba.com 
Cc:        Lang Hames <lhames at gmail.com>, Clang Dev <
cfe-dev at lists.llvm.org> 
Date:        21.04.2017 21:50 
Subject:        Re: [cfe-dev] JIT doens't resolve address 
Sent by:        w at wdtz.org 



Hmm, I tried using your code (copy+pasted and then mass-dumped headers to 
fix includes), and it seems to work fine for me: 

https://gist.github.com/dtzWill/df84b64a73001532e3fcfe73a2cffbb9#file-test-log 


Do you get different results when using your LLVM? If not, can you 
identify the differences between your code and what I constructed from 
your snippets? 

I noticed "PAUSE", are you on Windows? I'm not sure what the 
functionality/status of the JIT on Windows is, perhaps someone else can 
comment on that. 

~Will 

On Fri, Apr 21, 2017 at 1:03 AM, via cfe-dev <cfe-dev at lists.llvm.org> 
wrote: 
Hello Lang, 

the Code for my jit_main is a normal printf-HelloWorld program. I opended 
the file with notepad and found the following: 
; Function Attrs: noinline norecurse uwtable 
define i32 @main() #0 { 
entry: 
  %retval = alloca i32, align 4 
  store i32 0, i32* %retval, align 4 
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([35 x 
i8], [35 x i8]* 
@"\01??_C at _0CD@CMJEAMCD at Planschbeckilein?5sagt?5Halloilein@", i32 0, i32 
0)) 
  %call1 = call i32 @system(i8* getelementptr inbounds ([6 x i8], [6 x 
i8]* @"\01??_C at _05DIAHPDGL@PAUSE?$AA@", i32 0, i32 0)) 
  ret i32 0 
}





So... there is a main... Anyway! The code for the main is this one: 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
        printf("Planschbeckilein sagt Halloilein!\n"); 
        system("PAUSE"); 

        return 0; 
}





Kind regards 
Björn 



From:        Lang Hames <lhames at gmail.com> 
To:        bjoern.gaier at horiba.com 
Cc:        Clang Dev <cfe-dev at lists.llvm.org> 
Date:        20.04.2017 22:54 
Subject:        Re: [cfe-dev] JIT doens't resolve address 




Hi Bjoern, 

Sorry - I just noticed that the address for your "main" function has come 
back as '0'. In this case the answer is even simpler: The JIT never found 
the function at all, and so definitely didn't have any external symbols to 
resolve, so it never called the resolver. 

A failure to find main has three likely causes: 

(1) jit_main.ll does not define main, 
(2) jit_main.ll defines main with private/internal linkage (the JIT can't 
see private/internal symbols in general) 
(3) jit_main.ll defines main with external linkage, but a system mangling 
is applied (e.g. on MacOSX 'main' is mangled to '_main'). The mangler code 
in your findSymbol function *should* correct for this, but this may fail 
if the default data layout for your TargetMachine varies from the Module's 
DataLayout. 

Can you share the contents of your jit_main.ll Module? 

Cheers, 
Lang. 
    

On Thu, Apr 20, 2017 at 1:35 PM, Lang Hames <lhames at gmail.com> wrote: 
HI Bjoern, 

There are two kinds of symbol lookup in the JIT: 

(1) You want to find a symbol defined JIT'd code. This is what 
"findSymbol" on the JIT class does. 

(2) The JIT wants to fix up a module that contains references to symbols 
defined elsewhere (either in your program, or in other JIT'd code). This 
is the SymbolResolver's job. 

So assuming your main function in main.ll is trivial, e.g. 

int main() { 
  return 0; 
} 

then your findSymbol call will return the address of the JIT'd main 
without ever needing to look anything up in the resolver. 

If, on the other hand, your main function contains an external reference, 
e.g. 

int main() { 
  printf("Hello, World!"); // Reference to externally defined function 
printf. 
  return 0; 
} 

Then you'll receive a call back on your resolver looking for the address 
of printf. 

Hope this helps! 

Cheers, 
Lang. 

On Thu, Apr 20, 2017 at 6:43 AM, via cfe-dev <cfe-dev at lists.llvm.org> 
wrote: 
Hello LLVM-World, 

I was following the "Building a JIT in LLVM"-Tutorial and tried to load a 
normal main. My code is the following: 
class Jitter 
{ 
private: 
  std::unique_ptr<TargetMachine> TM; 
  const DataLayout DL; 
  ObjectLinkingLayer<> ObjectLayer; 
  IRCompileLayer<decltype(ObjectLayer)> CompileLayer; 

public: 
  typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandle; 

  Jitter() : TM(EngineBuilder().selectTarget()), DL(TM->
createDataLayout()), 
      CompileLayer(ObjectLayer, SimpleCompiler(*TM)) 
  {printf("!"); 
        llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 
  } 

  TargetMachine &getTargetMachine() { return *TM; } 

  ModuleHandle addModule(std::unique_ptr<Module> &&M) { 
  // Build our symbol resolver: 
  // Lambda 1: Look back into the JIT itself to find symbols that are part 
of 
  //           the same "logical dylib". 
  // Lambda 2: Search for external symbols in the host process. 
  auto Resolver = createLambdaResolver( 
      [&](const std::string &Name) 
      { 
                printf("FLUSH :0\n"); 

        if (auto Sym = CompileLayer.findSymbol(Name, false)) 
          return Sym; 
        return JITSymbol(nullptr); 
      }, 
      [](const std::string &S) 
          { 
                  printf("PLUSH :0\n"); 

        if (auto SymAddr = 
              RTDyldMemoryManager::getSymbolAddressInProcess(S)) 
          return JITSymbol(SymAddr, JITSymbolFlags::Exported); 
        return JITSymbol(nullptr); 
      }); 

  // Build a singleton module set to hold our module. 
  std::vector<std::unique_ptr<Module>> Ms; 
  Ms.push_back(std::move(M)); 

  // Add the set to the JIT with the resolver we created above and a newly 

  // created SectionMemoryManager. 
  return CompileLayer.addModuleSet(std::move(Ms), 
                                   make_unique<SectionMemoryManager>(), 
                                   std::move(Resolver)); 
} 

JITSymbol findSymbol(const std::string Name) { 
  std::string MangledName; 
  raw_string_ostream MangledNameStream(MangledName); 
  Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 
  printf("Tzearch for: %s\n\n", MangledNameStream.str()); 
  return CompileLayer.findSymbol(MangledNameStream.str(), false); 
} 

void removeModule(ModuleHandle H) { 
  CompileLayer.removeModuleSet(H); 
} 

};






And calling from main with: 
int main() 
{ 
        llvm::InitializeNativeTarget(); 
        llvm::InitializeNativeTargetAsmPrinter(); 
        llvm::InitializeNativeTargetAsmParser(); 

        llvm::LLVMContext context; 
        llvm::SMDiagnostic dia; 

        std::unique_ptr<llvm::Module> M = llvm::parseIRFile(
"./jit_main.ll", dia, context); 
        Jitter jit; 
        printf("Wuff?"); 
        Jitter::ModuleHandle h = jit.addModule(std::move(M)); 
        printf("KNUFF!\n"); 

        printf("Kuchen! 0x%p\n", jit.findSymbol("main").getAddress()); 

        system("PAUSE"); 
        return 0; 
}





The Code runs without a fail, but when the programm tries to resolve 
"main" the address is 0. The strange thing: the printf "FLUSH :0\n" and "
PLUSH :0\n" are never called, so did the code never compiled? What I'm 
doing wrong? 

Kind regards 
Björn
Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima. 
_______________________________________________
cfe-dev mailing list
cfe-dev at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev





Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima. 

_______________________________________________
cfe-dev mailing list
cfe-dev at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev




Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima. 



Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima. 



Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima.



Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, 
USt.ID-Nr. DE 114 165 789
Geschäftsführer: Hiroshi Kawamura, Dr Hiroshi Nakamura, Markus Bode, Heiko 
Lampert, Takashi Nagano, Takeshi Fukushima.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170510/c8823534/attachment.html>


More information about the cfe-dev mailing list