Gaier, Bjoern via llvm-dev
2019-May-09 09:04 UTC
[llvm-dev] Can I use the JIT interface to create trampolines? (For functions and global values)
Dear LLVM-Mailing list (again), I still have another beginners question in my mind - thank you for your patience. Again I was playing around, but this time with llvm::Function. In an older question I learned, that I can replace a llvm::Function directly with an address. llvm::Function *function = mainModue->getFunction("puts"); function->replaceAllUsesWith( llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(llvm::IntegerType::get(context, 64), 0xF), function->getType() ) ); With this code I 'overloaded' the function "puts" with the address 0xF - that is what I was taught and it is functional. I also noticed that you can do the same with a llvm::GlobalValue - as said I'm still a beginner. Now I wonder can I replace the use of a specific function with the address of an address? (I think this is called a trampoline) In C++ I know that I could use a function pointer instead of a function call to achieve this. So... Deriving from that knowledge I would have to create a function pointer with the same signature as the function I want to replace. Is this possible with the llvm JIT interface? Can I simply use that value in the "replaceAllUsesWith" function? And would the same technique also work with a llvm::GlobalValue? Kind greetings and thank you for the help in advance Björn Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, USt.ID-Nr. DE 114 165 789 Geschäftsführer: Dr. Hiroshi Nakamura, Dr. Robert Plank, Markus Bode, Heiko Lampert, Takashi Nagano, Takeshi Fukushima. Junichi Tajika -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190509/5b94d7b2/attachment.html>
Tim Northover via llvm-dev
2019-May-09 10:21 UTC
[llvm-dev] Can I use the JIT interface to create trampolines? (For functions and global values)
Hi Bjoern, On Thu, 9 May 2019 at 10:05, Gaier, Bjoern via llvm-dev <llvm-dev at lists.llvm.org> wrote:> Now I wonder can I replace the use of a specific function with the address of an address? (I think this is called a trampoline)There are two ways to do this, if I understand properly. Taking puts as the primitive example again: call void @puts(i8* ...) It would be called a trampoline if you replaced this just as you did before with a call to 0xf: call void inttoptr(i64 15 to void(i8*)*)(i8* ...) and then at 0xf there's a sequence that loads the real function from somewhere and jumps to it. Maybe (AArch64 code here, just because it's what I'm most familiar with): adr x16, #12 // x16 now has the address of the .xword below ldr x16, [x16] br x16 .xword real_puts_address In reality you'd probably load from a GOT-like table you'd put elsewhere in memory. The alternative (closer to what you actually described with "address of an address"), would be if 0xf instead contained a bare pointer to the real function. In that case you'd have to iterate through all users of the function, and replace a call with something like: %fn.i8 = load i8*, i8** inttoptr(i64 15 to i8**) %fn = bitcast i8* %fn.i8 to void(i8*)* call void %fn(i8* ...) You'd probably use an IRBuilder to help you here, and eventually ReplaceAllUses of the original "call @puts" with that final indirected call. (There are no uses here because it returns void, but in general there may be). The main difference between the two can be seen as whether the trampoline is inlined or not.> Can I simply use that value in the "replaceAllUsesWith" function?Not in the second case, but mostly yes if you use an actual trampoline.> And would the same technique also work with a llvm::GlobalValue?The trampoline wouldn't because there's no call involved for normal globals. The second technique of introducing an extra load explicitly would work for uses inside a function. Another issue you might have to deal with is if one global variable references another: @my_functions = global [3 x i8*] [i8* bitcast(void(i8*)* @puts to i8*), ...] Obviously you can't introduce a load there. The trampoline might work still if you only expect functions to be called, but may or may not have issues if people start comparing pointers for equality (depending on what you want to happen). It's likely to be an even bigger problem for non-functions. Cheers. Tim.
Alex Denisov via llvm-dev
2019-May-09 10:22 UTC
[llvm-dev] Can I use the JIT interface to create trampolines? (For functions and global values)
Hi Björn, No sure it exactly matches your issue, but we had a similar problem. TL;DR: you can achieve this by manipulating IR and a little help from JIT. Here is a high-level algorithm of what we did: Created an external global variable (GlobalFunctionPointer) with the same type as the function (basically a function pointer). Created a copy of the function, e.g. foobar -> foobar_copy. Replace the body of the original function with something like this (pseudocode): define foobar(a, b, c) { ptr = load @GlobalFunctionPointer call ptr(a, b, c) } Then, when you add your program into JIT you will hit the unresolved external symbol (GlobalFunctionPointer) that you should hook up to an address under your control: Something like this: SymbolInfo Resolver::findSymbol(const std::string &name) { if (name == "GlobalFunctionPointer") { return SymbolInfo((uint64_t)trampoline, JITSymbolFlags::Exported); } return SymbolInfo(nullptr); } Where the trampoline is a pointer, which can hold the address of a function you want to redirect your call to, e.g.: uint64_t *trampoline = new uint64_t; .... *trampoline = jit.getFunctionAddess("foobar_copy"); == I hope it gives you an idea of how that can be done.> On 9. May 2019, at 11:04, Gaier, Bjoern via llvm-dev <llvm-dev at lists.llvm.org> wrote: > > Dear LLVM-Mailing list (again), > > I still have another beginners question in my mind - thank you for your patience. > > Again I was playing around, but this time with llvm::Function. In an older question I learned, that I can replace a llvm::Function directly with an address. > > llvm::Function *function = mainModue->getFunction("puts"); > function->replaceAllUsesWith( > llvm::ConstantExpr::getIntToPtr( > llvm::ConstantInt::get(llvm::IntegerType::get(context, 64), 0xF), > function->getType() > ) > ); > With this code I 'overloaded' the function "puts" with the address 0xF - that is what I was taught and it is functional. I also noticed that you can do the same with a llvm::GlobalValue - as said I'm still a beginner. > > Now I wonder can I replace the use of a specific function with the address of an address? (I think this is called a trampoline) > In C++ I know that I could use a function pointer instead of a function call to achieve this. > > So... Deriving from that knowledge I would have to create a function pointer with the same signature as the function I want to replace. > Is this possible with the llvm JIT interface? Can I simply use that value in the "replaceAllUsesWith" function? > And would the same technique also work with a llvm::GlobalValue? > > Kind greetings and thank you for the help in advance > Björn > Als GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, USt.ID-Nr. DE 114 165 789 Geschäftsführer: Dr. Hiroshi Nakamura, Dr. Robert Plank, Markus Bode, Heiko Lampert, Takashi Nagano, Takeshi Fukushima. Junichi Tajika _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: Message signed with OpenPGP URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190509/53e60d77/attachment.sig>
Gaier, Bjoern via llvm-dev
2019-May-09 11:21 UTC
[llvm-dev] Can I use the JIT interface to create trampolines? (For functions and global values)
Hey Alex and Tim, Seems like both ideas are way more complex and over my current abilities then I thought... The basic idea behind this was to deal with references between two llvm::Modules. Normally I could link those cross references simply by adding both modules to the same ExecutionEngine. But I wondered if they could run in there own ExecutionEngines. When the object file is generated both modules would miss the references to each other, but at this state I'm in a deadlock. Because none of the modules is resolved, I can't look up any address from the other module. By using trampolines I could had provide the address for the trampoline and could had written the address the trampoline is pointing to, when both modules are done. -----Original Message----- From: Alex Denisov <1101.debian at gmail.com> Sent: Donnerstag, 9. Mai 2019 12:22 To: Gaier, Bjoern <Bjoern.Gaier at horiba.com> Cc: llvm-dev <llvm-dev at lists.llvm.org> Subject: Re: [llvm-dev] Can I use the JIT interface to create trampolines? (For functions and global values) Hi Björn, No sure it exactly matches your issue, but we had a similar problem. TL;DR: you can achieve this by manipulating IR and a little help from JIT. Here is a high-level algorithm of what we did: Created an external global variable (GlobalFunctionPointer) with the same type as the function (basically a function pointer). Created a copy of the function, e.g. foobar -> foobar_copy. Replace the body of the original function with something like this (pseudocode): define foobar(a, b, c) { ptr = load @GlobalFunctionPointer call ptr(a, b, c) } Then, when you add your program into JIT you will hit the unresolved external symbol (GlobalFunctionPointer) that you should hook up to an address under your control: Something like this: SymbolInfo Resolver::findSymbol(const std::string &name) { if (name == "GlobalFunctionPointer") { return SymbolInfo((uint64_t)trampoline, JITSymbolFlags::Exported); } return SymbolInfo(nullptr); } Where the trampoline is a pointer, which can hold the address of a function you want to redirect your call to, e.g.: uint64_t *trampoline = new uint64_t; .... *trampoline = jit.getFunctionAddess("foobar_copy"); == I hope it gives you an idea of how that can be done.> On 9. May 2019, at 11:04, Gaier, Bjoern via llvm-dev <llvm-dev at lists.llvm.org> wrote: > > Dear LLVM-Mailing list (again), > > I still have another beginners question in my mind - thank you for your patience. > > Again I was playing around, but this time with llvm::Function. In an older question I learned, that I can replace a llvm::Function directly with an address. > > llvm::Function *function = mainModue->getFunction("puts"); > function->replaceAllUsesWith( > llvm::ConstantExpr::getIntToPtr( > llvm::ConstantInt::get(llvm::IntegerType::get(context, 64), 0xF), > function->getType() > ) > ); > With this code I 'overloaded' the function "puts" with the address 0xF - that is what I was taught and it is functional. I also noticed that you can do the same with a llvm::GlobalValue - as said I'm still a beginner. > > Now I wonder can I replace the use of a specific function with the > address of an address? (I think this is called a trampoline) In C++ I know that I could use a function pointer instead of a function call to achieve this. > > So... Deriving from that knowledge I would have to create a function pointer with the same signature as the function I want to replace. > Is this possible with the llvm JIT interface? Can I simply use that value in the "replaceAllUsesWith" function? > And would the same technique also work with a llvm::GlobalValue? > > Kind greetings and thank you for the help in advance Björn Als GmbH > eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, USt.ID-Nr. > DE 114 165 789 Geschäftsführer: Dr. Hiroshi Nakamura, Dr. Robert > Plank, Markus Bode, Heiko Lampert, Takashi Nagano, Takeshi Fukushima. > Junichi Tajika _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-devAls GmbH eingetragen im Handelsregister Bad Homburg v.d.H. HRB 9816, USt.ID-Nr. DE 114 165 789 Geschäftsführer: Dr. Hiroshi Nakamura, Dr. Robert Plank, Markus Bode, Heiko Lampert, Takashi Nagano, Takeshi Fukushima. Junichi Tajika