From: Pierre-Marie de Rodat Date: Tue, 17 Mar 2020 12:01:45 +0000 (+0100) Subject: Enhance MIPS64 testing and simplify handling code for its peculiar relocations (... X-Git-Tag: v0.27~39 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3156d6f88feb85ad4ceaf142e9831b494a1f6e0b;p=pyelftools.git Enhance MIPS64 testing and simplify handling code for its peculiar relocations (#300) * Add handling for SHF_MASKOS section flags * Add readelf testcases for MIPS64 specificities * Simplify the decoding of MIPS64 relocations Instead of using "fake" fields to parse the relocation structure and then use complex shift/masks to recover the conveyed information (once for big endian binaries, twice for little endian ones), use fields actually described in the spec and use straightforward shifts to synthetize the "fake" fields. --- diff --git a/elftools/elf/descriptions.py b/elftools/elf/descriptions.py index c35b115..bacefd7 100644 --- a/elftools/elf/descriptions.py +++ b/elftools/elf/descriptions.py @@ -95,7 +95,8 @@ def describe_sh_flags(x): SH_FLAGS.SHF_WRITE, SH_FLAGS.SHF_ALLOC, SH_FLAGS.SHF_EXECINSTR, SH_FLAGS.SHF_MERGE, SH_FLAGS.SHF_STRINGS, SH_FLAGS.SHF_INFO_LINK, SH_FLAGS.SHF_LINK_ORDER, SH_FLAGS.SHF_OS_NONCONFORMING, - SH_FLAGS.SHF_GROUP, SH_FLAGS.SHF_TLS, SH_FLAGS.SHF_EXCLUDE): + SH_FLAGS.SHF_GROUP, SH_FLAGS.SHF_TLS, SH_FLAGS.SHF_MASKOS, + SH_FLAGS.SHF_EXCLUDE): s += _DESCR_SH_FLAGS[flag] if (x & flag) else '' if x & SH_FLAGS.SHF_MASKPROC: s += 'p' @@ -404,6 +405,7 @@ _DESCR_SH_FLAGS = { SH_FLAGS.SHF_OS_NONCONFORMING: 'O', SH_FLAGS.SHF_GROUP: 'G', SH_FLAGS.SHF_TLS: 'T', + SH_FLAGS.SHF_MASKOS: 'o', SH_FLAGS.SHF_EXCLUDE: 'E', } diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py index 2fb56a7..b9203c6 100644 --- a/elftools/elf/structs.py +++ b/elftools/elf/structs.py @@ -215,64 +215,56 @@ class ELFStructs(object): self.Elf_Chdr = Struct('Elf_Chdr', *fields) def _create_rel(self): - r_info = self.Elf_xword('r_info') - - # r_info is also taken apart into r_info_sym and r_info_type, plus - # r_info_type2 and r_info_type3 on ELF64 MIPS. This is done in Value - # to avoid endianity issues while parsing. + # r_info is also taken apart into r_info_sym and r_info_type. This is + # done in Value to avoid endianity issues while parsing. if self.elfclass == 32: - fields = [Value('r_info_sym', + fields = [self.Elf_xword('r_info'), + Value('r_info_sym', lambda ctx: (ctx['r_info'] >> 8) & 0xFFFFFF), Value('r_info_type', lambda ctx: ctx['r_info'] & 0xFF)] elif self.e_machine == 'EM_MIPS': # ELF64 MIPS - # The r_info field in MIPS ELF64 binaries (called r_raw_info, here) - # isn't a 64-bit field, but rather two 32-bit fields (the symbol - # index, then three bytes for relocation types). See the - # specification: - # - # Note that the specification describes the fields more directly, - # but here we stick to the general "r_info" field to be compatible - # with other architectures and simplify testing. - - def compute_r_info(ctx): - raw = ctx['r_raw_info'] - if not self.little_endian: - return raw - # little endian requires an additional byteswap - return (((raw & 0xffffffff) << 32) - | ((raw >> 56) & 0xff) - | ((raw >> 40) & 0xff00) - | ((raw >> 24) & 0xff0000) - | ((raw >> 8) & 0xff000000)) - - r_info = self.Elf_xword('r_raw_info') fields = [ - Value('r_info', compute_r_info), - Value('r_info_sym', - lambda ctx: (ctx['r_info'] >> 32) & 0xFFFFFFFF), - Value('r_info_type3', - lambda ctx: (ctx['r_info'] >> 16) & 0xFF), - Value('r_info_type2', - lambda ctx: (ctx['r_info'] >> 8) & 0xFF), - Value('r_info_type', - lambda ctx: ctx['r_info'] & 0xFF) + # The MIPS ELF64 specification + # (https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf) + # provides a non-standard relocation structure definition. + self.Elf_word('r_sym'), + self.Elf_byte('r_ssym'), + self.Elf_byte('r_type3'), + self.Elf_byte('r_type2'), + self.Elf_byte('r_type'), + + # Synthetize usual fields for compatibility with other + # architectures. This allows relocation consumers (including + # our readelf tests) to work without worrying about MIPS64 + # oddities. + Value('r_info_sym', lambda ctx: ctx['r_sym']), + Value('r_info_ssym', lambda ctx: ctx['r_ssym']), + Value('r_info_type', lambda ctx: ctx['r_type']), + Value('r_info_type2', lambda ctx: ctx['r_type2']), + Value('r_info_type3', lambda ctx: ctx['r_type3']), + Value('r_info', + lambda ctx: (ctx['r_sym'] << 32) + | (ctx['r_ssym'] << 24) + | (ctx['r_type3'] << 16) + | (ctx['r_type2'] << 8) + | ctx['r_type']), ] else: # Other 64 ELFs - fields = [Value('r_info_sym', + fields = [self.Elf_xword('r_info'), + Value('r_info_sym', lambda ctx: (ctx['r_info'] >> 32) & 0xFFFFFFFF), Value('r_info_type', lambda ctx: ctx['r_info'] & 0xFFFFFFFF)] self.Elf_Rel = Struct('Elf_Rel', - self.Elf_addr('r_offset'), - r_info, - *fields - ) + self.Elf_addr('r_offset'), + *fields) + + fields_and_addend = fields + [self.Elf_sxword('r_addend')] self.Elf_Rela = Struct('Elf_Rela', - self.Elf_addr('r_offset'), - r_info, - *(fields + [self.Elf_sxword('r_addend')]) + self.Elf_addr('r_offset'), + *fields_and_addend ) def _create_dyn(self): diff --git a/test/testfiles_for_readelf/mips64-relocs-be.o.elf b/test/testfiles_for_readelf/mips64-relocs-be.o.elf new file mode 100644 index 0000000..fb6d587 Binary files /dev/null and b/test/testfiles_for_readelf/mips64-relocs-be.o.elf differ diff --git a/test/testfiles_for_readelf/mips64-relocs-le.o.elf b/test/testfiles_for_readelf/mips64-relocs-le.o.elf new file mode 100644 index 0000000..028d413 Binary files /dev/null and b/test/testfiles_for_readelf/mips64-relocs-le.o.elf differ diff --git a/test/testfiles_for_readelf/mips64-relocs.c b/test/testfiles_for_readelf/mips64-relocs.c new file mode 100644 index 0000000..707b625 --- /dev/null +++ b/test/testfiles_for_readelf/mips64-relocs.c @@ -0,0 +1,19 @@ +/* This source was compiled for MIPS64 (big endian) and MIPS64EL (little + endial): + + mips64-unknown-linux-gnu-gcc -c mips64-relocs.c -o mips64-relocs-be.o.elf -mabi=64 + mips64el-unknown-linux-gnu-gcc -c mips64-relocs.c -o mips64-relocs-le.o.elf -mabi=64 +*/ + +extern struct { + int i, j; +} data; + +extern int bar (void); + +int +foo (int a) +{ + data.i += a; + data.j -= bar(); +}