+ def build_symbols_tables(self):
+ """Find out the globally available symbols, as well as the globally
+ undefined ones (which should be found in external libraries."""
+
+ # Gather the "extern" symbols from each input files.
+ for i in self.objs:
+ self.undefined_symbols.update(i.undefined_symbols)
+
+ # Make a dict with all the symbols declared globally.
+ # Key is the symbol name, value will later be set to the final
+ # virtual address. Currently, we're only interrested in the declaration.
+ # The virtual addresses are set to None, they'll be resolved later.
+ for i in self.objs:
+ for s in i.global_symbols:
+ if s in self.global_symbols:
+ raise RedefinedSymbol(s)
+ self.global_symbols[s] = None
+
+ # Add a few useful symbols. They'll be resolved ater as well.
+ self.global_symbols["_dt_debug"] = None
+ self.global_symbols["_DYNAMIC"] = None
+
+ # Find out which symbols aren't really defined anywhere
+ self.undefined_symbols.difference_update(self.global_symbols)
+
+
+ def build_external(self, with_jump=False, align_jump=True):
+ """
+ Generate a fake relocatable object, for dynamic linking.
+ """
+
+ # Find out all the undefined symbols. They're the one we'll need to resolve
+ # dynamically.
+ symbols = sorted(list(self.undefined_symbols))
+
+ # Those three will soon be known...
+ symbols.remove('_bold__functions_count')
+ symbols.remove('_bold__functions_hash')
+ symbols.remove('_bold__functions_pointers')
+
+ # Create the fake ELF object.
+ fo = Elf64() # Don't care about most parts of ELF header (?)
+ fo.filename = "Internal dynamic linker"
+
+ # We need a .data section, a .bss section and a possibly a .text section
+ data_shdr = Elf64_Shdr()
+ data_shdr.sh_type = SHT_PROGBITS
+ data_shdr.sh_flags = (SHF_WRITE | SHF_ALLOC)
+ data_shdr.sh_size = len(symbols) * 4
+ fmt = "<" + "I" * len(symbols)
+ data_shdr.content = BinArray(struct.pack(fmt, *[hash_name(s) for s in symbols]))
+ fo.shdrs.append(data_shdr)
+ fo.sections['.data'] = data_shdr
+
+ bss_shdr = Elf64_Shdr()
+ bss_shdr.sh_type = SHT_NOBITS
+ bss_shdr.sh_flags = (SHF_WRITE | SHF_ALLOC)
+ bss_shdr.sh_size = len(symbols) * 8
+ bss_shdr.content = BinArray("")
+ fo.shdrs.append(bss_shdr)
+ fo.sections['.bss'] = bss_shdr
+
+ if with_jump:
+ text_shdr = Elf64_Shdr()
+ text_shdr.sh_type = SHT_PROGBITS
+ text_shdr.sh_flags = (SHF_ALLOC | SHF_EXECINSTR)
+ text_shdr.sh_size = len(symbols) * 8
+ if align_jump:
+ fmt = '\xff\x25\x00\x00\x00\x00\x00\x00' # ff 25 = jmp [rel label]
+ jmp_size = 8
+ else:
+ fmt = '\xff\x25\x00\x00\x00\x00'
+ jmp_size = 6
+ text_shdr.content = BinArray(fmt * len(symbols))
+ fo.shdrs.append(text_shdr)
+ fo.sections['.text'] = text_shdr
+
+ # Cheating here. All symbols declared as global so we don't need to create
+ # a symtab from scratch.
+ fo.global_symbols = {}
+ fo.global_symbols['_bold__functions_count'] = (SHN_ABS, len(symbols))
+ fo.global_symbols['_bold__functions_hash'] = (data_shdr, 0)
+ fo.global_symbols['_bold__functions_pointers'] = (bss_shdr, 0)
+
+ for n, i in enumerate(symbols):
+ # The hash is always in .data
+ h = "_bold__hash_%s" % i
+ fo.global_symbols[h] = (data_shdr, n * 4) # Section, offset
+
+ if with_jump:
+ # the symbol is in .text, can be called directly
+ fo.global_symbols[i] = (text_shdr, n * jmp_size)
+ # another symbol can be used to reference the pointer, just in case.
+ p = "_bold__%s" % i
+ fo.global_symbols[p] = (bss_shdr, n * 8)
+
+ else:
+ # The symbol is in .bss, must be called indirectly
+ fo.global_symbols[i] = (bss_shdr, n * 8)
+
+ if with_jump:
+ # Add relocation entries for the jumps
+ # Relocation will be done for the .text, for every jmp instruction.
+ class dummy: pass
+ rela_shdr = Elf64_Shdr()
+ rela_shdr.sh_type = SHT_RELA
+ # rela_shdr.sh_info = fo.shdrs.index(text_shdr)
+ rela_shdr.target = text_shdr
+ rela_shdr.sh_flags = 0
+ rela_shdr._content = dummy() # We only need a container for relatab...
+ relatab = [] # Prepare a relatab
+ rela_shdr.content.relatab = relatab
+
+ for n, i in enumerate(symbols):
+ # Create a relocation entry for each symbol
+ reloc = dummy()
+ reloc.r_offset = (n * jmp_size) + 2 # Beginning of the cell to update
+ reloc.r_addend = -4
+ reloc.r_type = R_X86_64_PC32
+ reloc.symbol = dummy()
+ reloc.symbol.st_shndx = SHN_UNDEF
+ reloc.symbol.name = "_bold__%s" % i
+ # reloc.symbol.st_value = 0
+ relatab.append(reloc)
+ fo.shdrs.append(rela_shdr)
+ fo.sections['.rela.text'] = rela_shdr
+
+ # Ok, let's add this fake object
+ self.objs.append(fo)
+
+