From 3156d6f88feb85ad4ceaf142e9831b494a1f6e0b Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Tue, 17 Mar 2020 13:01:45 +0100 Subject: [PATCH] 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. --- elftools/elf/descriptions.py | 4 +- elftools/elf/structs.py | 80 ++++++++---------- .../mips64-relocs-be.o.elf | Bin 0 -> 2008 bytes .../mips64-relocs-le.o.elf | Bin 0 -> 2008 bytes test/testfiles_for_readelf/mips64-relocs.c | 19 +++++ 5 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 test/testfiles_for_readelf/mips64-relocs-be.o.elf create mode 100644 test/testfiles_for_readelf/mips64-relocs-le.o.elf create mode 100644 test/testfiles_for_readelf/mips64-relocs.c 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 0000000000000000000000000000000000000000..fb6d587ff5474780e116e9dc9850a0ee6716e64f GIT binary patch literal 2008 zcmbtVPiWIn82^%Vt6Fv4R46JMkxCW!s5l0SV6^BIbPR{!(WHN}!rGK31wCze7Q9aI zu%idTs|Tl|7mqu7YmXjP5O#~dm*llCY2!gZ`tp6>@B8<@_r9bXx9;6mRfUG6&_2i# zFtk9(6m+6283AU{3>~(2{9XSemHZE+`|qisZT~1DgK=l9B`0B? z^lUP({=_2|bj&Q*C3gSr$|`d@Uejp{&9s`0b<>6#gmh|MVy#-;>e&pY#RXzjr`4*r zkq86JOwa2!t)5qR#U}oX>xdT9pPVNn%Df$M!Q`tx0Z`1dAsj-kev9%OIZ*FpK dq6F%@NZ|h=GRgI4VMvMBwxXa7IT-RV{tt0_gYp0X literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..028d413725e2abe92dcf5609cf17f3022aa807c9 GIT binary patch literal 2008 zcmbVNO=uHA6#kM;YwBNPst~m3id3SsL&Q>01XqJrK})d+9^GxzG|*&2b_;rH@ho_) z;Gstkf>#e#MK2zE^p+ewsvz{XzPCG*T_>AMU&wxMzW2WOW+pS6%{ve7W-}Qm%OH<< zq*$Poi~K`?X@#zZaU929uv;(Vb710AP{PMx>er3|Ox~F3y(WB9pDJttg)Aw)z6V}( zf!i;EZ?Dc5988tC5_8pej1#a>{0@xmo1{fQo+HhLLNzhwe2V}4Vo>ic_3l#dZUwvb zJbIy)<7}C7gpjuU4;{<@trjm&|M8s;J=B zII;EC1~Rl)$Z3UGk~9wI@Vj3-88hPPBxxA*Ni%~grI~@TG@7c64B8j zA(q`{v(}4^n6{m#W54l5c zCC~fJee!Z#l6X<_`c3J{xDI;%X-eRl2i0F8EuD=vO;=4VY}pH+Kv|*!m84!5Hz{yA z(yNpZ^D;rLQw5b?@kR)lCQrx79?kBd0TQrR3F}dzFd0$C&Z=ox6;Uz z+*Qd{2$QDt#Ux3-Dyz^X?r#t<{AZ73g8q9eol53$d>IuBtjWYhiG2V0^6Ts8H?Dqm bxXK4vl>a}HruXOfWSV|klAB2}`MUleqf3MF literal 0 HcmV?d00001 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(); +} -- 2.30.2