Loader Mode and Code Generation

Running and Debugging the Loader

Egalito’s custom loader can be invoked with:

$ cd src ; ./loader ex/hello ; cd -

Note that we have not been focusing on loader development and ELF generation mode is generally more reliable. When debugging the loader, make use of symbols.elf which Egalito generates at load-time:

$ gdb -q --args ./loader ex/hello
Reading symbols from ./loader...done.
(gdb) l loader.cpp:172
167         EgalitoTLS::setSandbox(shufflingSandbox);
168         EgalitoTLS::setGSTable(gsTable);
169     }
171     // jump to the target program (never returns)
172     start2();
173     //_start2();
174 }
176 void EgalitoLoader::otherPasses() {
(gdb) b loader.cpp:172
Breakpoint 1 at 0x6013ac09: file load/loader.cpp, line 172.
(gdb) r
Breakpoint 1, EgalitoLoader::run (this=this@entry=0x7fffffffe480) at load/loader.cpp:172
172     start2();
(gdb) si
0x0000000040136e96 in ?? ()
(gdb) add-symbol-file symbols.elf 0
add symbol table from file "symbols.elf" at
    .text_addr = 0x0
(y or n) y
Reading symbols from symbols.elf...(no debugging symbols found)...done.
(gdb) disass
Dump of assembler code for function _start2$new:
=> 0x0000000040136e96 <+0>: push   %rbx
   0x0000000040136e97 <+1>: callq  *-0x2ec96abd(%rip)        # 0x114a03e0
   0x0000000040136e9d <+7>: pop    %rbx
   0x0000000040136e9e <+8>: mov    -0x2ec963c5(%rip),%rax        # 0x114a0ae0
   0x0000000040136ea5 <+15>:        mov    (%rax),%rsp
   0x0000000040136ea8 <+18>:        xor    %rdx,%rdx
   0x0000000040136eab <+21>:        mov    -0x2ec9646a(%rip),%rbx        # 0x114a0a48
   0x0000000040136eb2 <+28>:        jmpq   *(%rbx)
   0x0000000040136eb4 <+30>:        hlt
End of assembler dump.

We set a breakpoint at the place where Egalito first jumps to transformed code. The dynamically-generated code within 0x40000000 was unknown until we told gdb about the new symbols. _start2 is the original code, _start2$new is the transformed code; every symbol simply has $new appended. The first indirect call invokes constructors, the last indirect jump targets the program entry point _start$new. You can set breakpoints e.g. at main$new.

Runtime Code Generation

To perform runtime code generation, create a Sandbox to store new code. Then use a backing to decide how that code is stored We provide MemoryBacking which is an mmap directly at the target address, useful for code generation within the target process, and also MemoryBufferBacking which stores the generated code in an std::string, useful for writing code to a file or generating code at an address that cannot otherwise be mapped (e.g. kernel code generation). See ConductorSetup::makeLoaderSandbox for an example.

Now, assign codes to new addresses and then generate it. For these two steps, see transform/generator.h.