@@ -21,17 +21,24 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
2121 if (UNLIKELY (!validate_header (elf))) {
2222 throw MachineException (" Invalid ELF header! Not a 64-bit program?" );
2323 }
24- if (UNLIKELY (elf->e_type != ET_EXEC)) {
25- throw MachineException (" Invalid ELF type: Not an executable!" );
24+ bool is_dynamic = false ;
25+ if (elf->e_type == ET_DYN) {
26+ is_dynamic = true ;
27+ this ->m_image_base = DYLINK_BASE;
28+ }
29+ else if (elf->e_type == ET_EXEC) {
30+ this ->m_image_base = 0x0 ;
31+ } else {
32+ throw MachineException (" Invalid ELF type: Not a static or dynamic executable!" );
2633 }
2734
2835 // enumerate & load loadable segments
2936 const auto program_headers = elf->e_phnum ;
3037 if (UNLIKELY (program_headers <= 0 )) {
3138 throw MachineException (" ELF with no program-headers" );
3239 }
33- if (UNLIKELY (program_headers >= 16 )) {
34- throw MachineException (" ELF with too many program-headers. Dynamic? " );
40+ if (UNLIKELY (program_headers >= 64 )) {
41+ throw MachineException (" ELF with too many program-headers" );
3542 }
3643 if (UNLIKELY (elf->e_phoff + program_headers * sizeof (Elf64_Phdr) > binary.size ())) {
3744 throw MachineException (" ELF program-headers are outside the binary" );
@@ -48,8 +55,8 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
4855
4956 const auto * phdr = (Elf64_Phdr*) (binary.data () + elf->e_phoff );
5057 const auto program_begin = phdr->p_vaddr ;
51- this ->m_start_address = elf->e_entry ;
52- this ->m_stack_address = program_begin;
58+ this ->m_start_address = this -> m_image_base + elf->e_entry ;
59+ this ->m_stack_address = this -> m_image_base + program_begin;
5360 this ->m_heap_address = 0x0 ;
5461
5562 int seg = 0 ;
@@ -61,13 +68,15 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
6168 }
6269
6370 // Detect overlapping segments
64- for (const auto * ph = phdr; ph < hdr; ph++) {
65- if (hdr->p_type == PT_LOAD && ph->p_type == PT_LOAD)
66- if (ph->p_vaddr < hdr->p_vaddr + hdr->p_filesz &&
67- ph->p_vaddr + ph->p_filesz >= hdr->p_vaddr ) {
68- // Normally we would not care, but no normal ELF
69- // has overlapping segments, so treat as bogus.
70- throw MachineException (" Overlapping ELF segments" );
71+ if (hdr->p_type == PT_LOAD) {
72+ for (const auto * ph = phdr; ph < hdr; ph++) {
73+ if (ph->p_type == PT_LOAD &&
74+ ph->p_vaddr < hdr->p_vaddr + hdr->p_filesz &&
75+ ph->p_vaddr + ph->p_filesz >= hdr->p_vaddr ) {
76+ // Normally we would not care, but no normal ELF
77+ // has overlapping segments, so treat as bogus.
78+ throw MachineException (" Overlapping ELF segments" , hdr->p_vaddr );
79+ }
7180 }
7281 }
7382
@@ -96,6 +105,7 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
96105 }
97106
98107 /* Make sure mmap starts at a sane offset */
108+ this ->m_heap_address += this ->m_image_base ;
99109 this ->m_mm = this ->mmap_start ();
100110
101111 /* If there is not enough room for stack, move it */
@@ -104,7 +114,10 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
104114 this ->m_stack_address = this ->mmap_allocate (STACK_SIZE) + STACK_SIZE;
105115 }
106116
107- // this->relocate_section(".rela.plt", ".symtab");
117+ /* Dynamic executables require some extra work, like relocation */
118+ if (is_dynamic) {
119+ this ->dynamic_linking (binary, options);
120+ }
108121
109122 if (options.verbose_loader ) {
110123 printf (" * Entry is at %p\n " , (void *) m_start_address);
@@ -127,19 +140,28 @@ void Machine::elf_load_ph(std::string_view binary, const MachineOptions& options
127140 if (binary.size () < hdr->p_offset + len) {
128141 throw MachineException (" Not enough room for ELF program segment" , len);
129142 }
130- if (hdr->p_vaddr + len < hdr->p_vaddr ) {
143+ const address_t load_address = this ->m_image_base + hdr->p_vaddr ;
144+ if (load_address + len < load_address) {
131145 throw MachineException (" Bogus ELF segment virtual base" , hdr->p_vaddr );
132146 }
133147
134148 if (options.verbose_loader ) {
135149 printf (" * Loading segment of size %zu from %p to virtual %p\n " ,
136- len, src, (void *) hdr-> p_vaddr );
150+ len, src, (void *) load_address );
137151 }
138152
139- if (memory.safely_within (hdr->p_vaddr , len)) {
140- std::memcpy (memory.at (hdr->p_vaddr ), src, len);
153+ if (UNLIKELY (load_address < this ->m_image_base )) {
154+ throw MachineException (" Bogus ELF segment virtual base" , hdr->p_vaddr );
155+ }
156+ if (memory.safely_within (load_address, len)) {
157+ std::memcpy (memory.at (load_address), src, len);
141158 } else {
142- throw MachineException (" Unsafe PT_LOAD segment or executable too big" , hdr->p_vaddr );
159+ if (options.verbose_loader ) {
160+ printf (" Segment at %p is too large or not safely within physical base at %p. Size: %zu vs %p\n " ,
161+ (void *)load_address, (void *)memory.safebase , len, (void *)(memory.physbase + memory.size ));
162+ fflush (stdout);
163+ }
164+ throw MachineException (" Unsafe PT_LOAD segment or executable too big" , load_address);
143165 }
144166}
145167
@@ -190,7 +212,7 @@ static const Elf64_Sym* resolve_symbol(std::string_view binary, const char* name
190212uint64_t Machine::address_of (const char * name) const
191213{
192214 const auto * sym = resolve_symbol (m_binary, name);
193- return (sym) ? sym->st_value : 0x0 ;
215+ return (sym) ? this -> m_image_base + sym->st_value : 0x0 ;
194216}
195217std::string Machine::resolve (uint64_t rip) const
196218{
@@ -200,6 +222,9 @@ std::string Machine::resolve(uint64_t rip) const
200222 const auto * str_hdr = section_by_name (m_binary, " .strtab" );
201223 if (UNLIKELY (str_hdr == nullptr )) return " " ;
202224
225+ if (UNLIKELY (rip < this ->m_image_base )) return " " ;
226+ const address_t relative_rip = rip - this ->m_image_base ;
227+
203228 const auto * symtab = elf_sym_index (m_binary, sym_hdr, 0 );
204229 const size_t symtab_ents = sym_hdr->sh_size / sizeof (Elf64_Sym);
205230 const char * strtab = elf_offset<char >(m_binary, str_hdr->sh_offset );
@@ -209,9 +234,9 @@ std::string Machine::resolve(uint64_t rip) const
209234 /* Only look at functions (for now). Old-style symbols have no FUNC. */
210235 if (symtab[i].st_info & STT_FUNC) {
211236 /* Direct matches only (for now) */
212- if (rip >= symtab[i].st_value && rip < symtab[i].st_value + symtab[i].st_size )
237+ if (relative_rip >= symtab[i].st_value && relative_rip < symtab[i].st_value + symtab[i].st_size )
213238 {
214- const uint64_t offset = rip - symtab[i].st_value ;
239+ const uint64_t offset = relative_rip - symtab[i].st_value ;
215240 char result[2048 ];
216241 int len = snprintf (result, sizeof (result),
217242 " %s + 0x%lX" , &strtab[symtab[i].st_name ], offset);
@@ -225,49 +250,55 @@ std::string Machine::resolve(uint64_t rip) const
225250 return " (unknown)" ;
226251}
227252
228- void Machine::relocate_section (const char * section_name, const char * sym_section)
253+ bool Machine::relocate_section (const char * section_name, const char * sym_section)
229254{
230255 const auto * rela = section_by_name (m_binary, section_name);
231256 if (rela == nullptr ) {
232257 printf (" No such section: %s\n " , section_name);
233- return ;
258+ return false ;
234259 }
235260 const auto * dyn_hdr = section_by_name (m_binary, sym_section);
236261 if (dyn_hdr == nullptr ) {
237262 printf (" No such symbol section: %s\n " , sym_section);
238- return ;
263+ return false ;
264+ }
265+ const size_t rela_ents = rela->sh_size / sizeof (Elf64_Rela);
266+ if (rela_ents > 16384 ) {
267+ throw MachineException (" Too many relocations" , rela_ents);
239268 }
240- const size_t rela_ents = rela->sh_size / rela->sh_entsize ;
241- printf (" Rela ents: %zu\n " , rela_ents);
242269
243- auto * rela_addr = elf_offset <Elf64_Rela>(m_binary, rela->sh_offset );
270+ auto * rela_addr = elf_offset_array <Elf64_Rela>(m_binary, rela->sh_offset , rela_ents );
244271 for (size_t i = 0 ; i < rela_ents; i++)
245272 {
246- const uint8_t type = ELF64_R_TYPE (rela_addr[i].r_info );
247- if (type == R_X86_64_IRELATIVE)
248- {
249- const uint32_t symidx = ELF64_R_SYM (rela_addr[i].r_info );
250- // auto* sym = elf_sym_index(m_binary, dyn_hdr, symidx);
251- const int32_t addend = rela_addr[i].r_addend ;
252- const uint64_t addr = rela_addr[i].r_offset ;
253- printf (" Rela ent %zu with addend 0x%X = 0x%lX\n " , i, addend, addr);
254- auto * entry = (address_t *) memory.at (addend, 8 );
255- #ifdef TINYKVM_ARCH_AMD64
256- *entry = interrupt_header ().vm64_dso ;
257- #endif
273+ const auto symidx = ELF64_R_SYM (rela_addr[i].r_info );
274+ const Elf64_Sym* sym = elf_sym_index (m_binary, dyn_hdr, symidx);
258275
259- /* auto* entry = elf_offset<address_t> (m_binary, rela_addr[i].r_offset);
260- auto* final = elf_offset<address_t> (m_binary, sym->st_value);
261- if constexpr (true)
262- {
263- printf("Relocating rela %zu with sym idx %u where 0x%lX -> 0x%lX\n",
264- i, symidx, rela_addr[i].r_offset, sym->st_value);
276+ const auto rtype = ELF64_R_TYPE (rela_addr[i].r_info );
277+ if (rtype != R_X86_64_RELATIVE) {
278+ if constexpr (VERBOSE_LOADER) {
279+ printf (" Skipping non-relative relocation: %s\n " , &m_binary[sym->st_name ]);
280+ }
281+ continue ;
282+ }
283+
284+ const address_t addr = this ->m_image_base + rela_addr[i].r_offset ;
285+ if (memory.safely_within (addr, sizeof (address_t ))) {
286+ *(address_t *) memory.safely_at (addr, sizeof (address_t )) = this ->m_image_base + sym->st_value ;
287+ } else if (false ) {
288+ if constexpr (VERBOSE_LOADER) {
289+ printf (" Relocation failed: %s\n " , &m_binary[sym->st_name ]);
265290 }
266- // *(address_t*) entry = (address_t) (uintptr_t) final;
267- *(address_t*) entry = interrupt_header().vm64_gettimeofday;
268- */
269291 }
270292 }
293+ return true ;
294+ }
295+
296+ void Machine::dynamic_linking (std::string_view binary, const MachineOptions& options)
297+ {
298+ (void )binary;
299+ (void )options;
300+ this ->relocate_section (" .rela.dyn" , " .dynsym" );
301+ // this->relocate_section(".rela.plt", ".dynsym");
271302}
272303
273304}
0 commit comments