initial support for PPC64LE (#360)
authorNick Desaulniers <nickdesaulniers@users.noreply.github.com>
Sat, 15 May 2021 03:34:21 +0000 (20:34 -0700)
committerGitHub <noreply@github.com>
Sat, 15 May 2021 03:34:21 +0000 (20:34 -0700)
* initial support for PPC64LE

See also:
https://openpowerfoundation.org/wp-content/uploads/2016/03/ABI64BitOpenPOWERv1.1_16July2015_pub4.pdf
3.4.1 Symbol Values
3.5.3 Relocation Types Table

Fixes #317
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
* remove references to LLVM_ADDR_SIG

elftools/elf/constants.py
elftools/elf/descriptions.py
elftools/elf/enums.py
elftools/elf/relocation.py
elftools/elf/structs.py
scripts/readelf.py
test/testfiles_for_readelf/powerpc64-relocs-le.o.elf [new file with mode: 0644]
test/testfiles_for_readelf/powerpc64-relocs.c [new file with mode: 0644]

index 2dc5071ffa7c84c772f55bfb8e5abb69126a58e7..fc55aacaf673452565123495576b9e68d2fcfadd 100644 (file)
@@ -27,6 +27,10 @@ class E_FLAGS(object):
     EF_ARM_ABI_FLOAT_SOFT=0x00000200
     EF_ARM_ABI_FLOAT_HARD=0x00000400
 
+    EF_PPC64_ABI_V0=0
+    EF_PPC64_ABI_V1=1
+    EF_PPC64_ABI_V2=2
+
     EF_MIPS_NOREORDER=1
     EF_MIPS_PIC=2
     EF_MIPS_CPIC=4
index 94da823448309747e22c5834dd18968cf7e865f6..82fdff65c43849d0279d36c0f396ab72679fc814 100644 (file)
@@ -9,8 +9,8 @@
 from .enums import (
     ENUM_D_TAG, ENUM_E_VERSION, ENUM_P_TYPE_BASE, ENUM_SH_TYPE_BASE,
     ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64,
-    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_MIPS,
-    ENUM_ATTR_TAG_ARM, ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
+    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
+    ENUM_RELOC_TYPE_MIPS, ENUM_ATTR_TAG_ARM, ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
 from .constants import (
     P_FLAGS, RH_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS)
 from ..common.py3compat import iteritems
@@ -84,7 +84,7 @@ def describe_sh_type(x):
         return _DESCR_SH_TYPE.get(x)
     elif (x >= ENUM_SH_TYPE_BASE['SHT_LOOS'] and
           x < ENUM_SH_TYPE_BASE['SHT_GNU_versym']):
-        return 'loos+%lx' % (x - ENUM_SH_TYPE_BASE['SHT_LOOS'])
+        return 'loos+0x%lx' % (x - ENUM_SH_TYPE_BASE['SHT_LOOS'])
     else:
         return _unknown
 
@@ -98,8 +98,9 @@ def describe_sh_flags(x):
             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'
+    if not x & SH_FLAGS.SHF_EXCLUDE:
+        if x & SH_FLAGS.SHF_MASKPROC:
+            s += 'p'
     return s
 
 
@@ -115,6 +116,17 @@ def describe_symbol_visibility(x):
     return _DESCR_ST_VISIBILITY.get(x, _unknown)
 
 
+def describe_symbol_local(x):
+    return '[<localentry>: ' + str(1 << x) + ']'
+
+
+def describe_symbol_other(x):
+    vis = describe_symbol_visibility(x['visibility'])
+    if x['local'] > 1 and x['local'] < 7:
+        return vis + ' ' + describe_symbol_local(x['local'])
+    return vis
+
+
 def describe_symbol_shndx(x):
     return _DESCR_ST_SHNDX.get(x, '%3s' % x)
 
@@ -129,6 +141,8 @@ def describe_reloc_type(x, elffile):
         return _DESCR_RELOC_TYPE_ARM.get(x, _unknown)
     elif arch == 'AArch64':
         return _DESCR_RELOC_TYPE_AARCH64.get(x, _unknown)
+    elif arch == '64-bit PowerPC':
+        return _DESCR_RELOC_TYPE_PPC64.get(x, _unknown)
     elif arch == 'MIPS':
         return _DESCR_RELOC_TYPE_MIPS.get(x, _unknown)
     else:
@@ -303,6 +317,7 @@ _DESCR_E_MACHINE = dict(
     EM_AARCH64='AArch64',
     EM_BLACKFIN='Analog Devices Blackfin',
     EM_PPC='PowerPC',
+    EM_PPC64='PowerPC64',
     RESERVED='RESERVED',
 )
 
@@ -545,6 +560,7 @@ _DESCR_RELOC_TYPE_i386 = _reverse_dict(ENUM_RELOC_TYPE_i386)
 _DESCR_RELOC_TYPE_x64 = _reverse_dict(ENUM_RELOC_TYPE_x64)
 _DESCR_RELOC_TYPE_ARM = _reverse_dict(ENUM_RELOC_TYPE_ARM)
 _DESCR_RELOC_TYPE_AARCH64 = _reverse_dict(ENUM_RELOC_TYPE_AARCH64)
+_DESCR_RELOC_TYPE_PPC64 = _reverse_dict(ENUM_RELOC_TYPE_PPC64)
 _DESCR_RELOC_TYPE_MIPS = _reverse_dict(ENUM_RELOC_TYPE_MIPS)
 
 _low_priority_D_TAG = (
index bebf7a7f32e9664e6be3bdec3e8405e13c3b3279..6be988cf7991c786c828b894b64bd3fba1a4814b 100644 (file)
@@ -461,6 +461,10 @@ ENUM_ST_VISIBILITY = dict(
     _default_=Pass,
 )
 
+ENUM_ST_LOCAL = dict(
+    _default_=Pass,
+)
+
 # st_shndx
 ENUM_ST_SHNDX = dict(
     SHN_UNDEF=0,
@@ -1146,3 +1150,130 @@ ENUM_ATTR_TAG_ARM = dict(
     TAG_VIRTUALIZATION_USE=68,
     TAG_MPEXTENSION_USE_OLD=70,
 )
+
+# https://openpowerfoundation.org/wp-content/uploads/2016/03/ABI64BitOpenPOWERv1.1_16July2015_pub4.pdf
+# See 3.5.3 Relocation Types Table.
+ENUM_RELOC_TYPE_PPC64 = dict(
+    R_PPC64_NONE=0,
+    R_PPC64_ADDR32=1,
+    R_PPC64_ADDR24=2,
+    R_PPC64_ADDR16=3,
+    R_PPC64_ADDR16_LO=4,
+    R_PPC64_ADDR16_HI=5,
+    R_PPC64_ADDR16_HA=6,
+    R_PPC64_ADDR14=7,
+    R_PPC64_ADDR14_BRTAKEN=8,
+    R_PPC64_ADDR14_BRNTAKEN=9,
+    R_PPC64_REL24=10,
+    R_PPC64_REL14=11,
+    R_PPC64_REL14_BRTAKEN=12,
+    R_PPC64_REL14_BRNTAKEN=13,
+    R_PPC64_GOT16=14,
+    R_PPC64_GOT16_LO=15,
+    R_PPC64_GOT16_HI=16,
+    R_PPC64_GOT16_HA=17,
+    R_PPC64_COPY=19,
+    R_PPC64_GLOB_DAT=20,
+    R_PPC64_JMP_SLOT=21,
+    R_PPC64_RELATIVE=22,
+    R_PPC64_UADDR32=24,
+    R_PPC64_UADDR16=25,
+    R_PPC64_REL32=26,
+    R_PPC64_PLT32=27,
+    R_PPC64_PLTREL32=28,
+    R_PPC64_PLT16_LO=29,
+    R_PPC64_PLT16_HI=30,
+    R_PPC64_PLT16_HA=31,
+    R_PPC64_SECTOFF=33,
+    R_PPC64_SECTOFF_LO=34,
+    R_PPC64_SECTOFF_HI=35,
+    R_PPC64_SECTOFF_HA=36,
+    R_PPC64_ADDR30=37,
+    R_PPC64_ADDR64=38,
+    R_PPC64_ADDR16_HIGHER=39,
+    R_PPC64_ADDR16_HIGHERA=40,
+    R_PPC64_ADDR16_HIGHEST=41,
+    R_PPC64_ADDR16_HIGHESTA=42,
+    R_PPC64_UADDR64=43,
+    R_PPC64_REL64=44,
+    R_PPC64_PLT64=45,
+    R_PPC64_PLTREL64=46,
+    R_PPC64_TOC16=47,
+    R_PPC64_TOC16_LO=48,
+    R_PPC64_TOC16_HI=49,
+    R_PPC64_TOC16_HA=50,
+    R_PPC64_TOC=51,
+    R_PPC64_PLTGOT16=52,
+    R_PPC64_PLTGOT16_LO=53,
+    R_PPC64_PLTGOT16_HI=54,
+    R_PPC64_PLTGOT16_HA=55,
+    R_PPC64_ADDR16_DS=56,
+    R_PPC64_ADDR16_LO_DS=57,
+    R_PPC64_GOT16_DS=58,
+    R_PPC64_GOT16_LO_DS=59,
+    R_PPC64_PLT16_LO_DS=60,
+    R_PPC64_SECTOFF_DS=61,
+    R_PPC64_SECTOFF_LO_DS=62,
+    R_PPC64_TOC16_DS=63,
+    R_PPC64_TOC16_LO_DS=64,
+    R_PPC64_PLTGOT16_DS=65,
+    R_PPC64_PLTGOT16_LO_DS=66,
+    R_PPC64_TLS=67,
+    R_PPC64_DTPMOD64=68,
+    R_PPC64_TPREL16=69,
+    R_PPC64_TPREL16_LO=70,
+    R_PPC64_TPREL16_HI=71,
+    R_PPC64_TPREL16_HA=72,
+    R_PPC64_TPREL64=73,
+    R_PPC64_DTPREL16=74,
+    R_PPC64_DTPREL16_LO=75,
+    R_PPC64_DTPREL16_HI=76,
+    R_PPC64_DTPREL16_HA=77,
+    R_PPC64_DTPREL64=78,
+    R_PPC64_GOT_TLSGD16=79,
+    R_PPC64_GOT_TLSGD16_LO=80,
+    R_PPC64_GOT_TLSGD16_HI=81,
+    R_PPC64_GOT_TLSGD16_HA=82,
+    R_PPC64_GOT_TLSLD16=83,
+    R_PPC64_GOT_TLSLD16_LO=84,
+    R_PPC64_GOT_TLSLD16_HI=85,
+    R_PPC64_GOT_TLSLD16_HA=86,
+    R_PPC64_GOT_TPREL16_DS=87,
+    R_PPC64_GOT_TPREL16_LO_DS=88,
+    R_PPC64_GOT_TPREL16_HI=89,
+    R_PPC64_GOT_TPREL16_HA=90,
+    R_PPC64_GOT_DTPREL16_DS=91,
+    R_PPC64_GOT_DTPREL16_LO_DS=92,
+    R_PPC64_GOT_DTPREL16_HI=93,
+    R_PPC64_GOT_DTPREL16_HA=94,
+    R_PPC64_TPREL16_DS=95,
+    R_PPC64_TPREL16_LO_DS=96,
+    R_PPC64_TPREL16_HIGHER=97,
+    R_PPC64_TPREL16_HIGHERA=98,
+    R_PPC64_TPREL16_HIGHEST=99,
+    R_PPC64_TPREL16_HIGHESTA=100,
+    R_PPC64_DTPREL16_DS=101,
+    R_PPC64_DTPREL16_LO_DS=102,
+    R_PPC64_DTPREL16_HIGHER=103,
+    R_PPC64_DTPREL16_HIGHERA=104,
+    R_PPC64_DTPREL16_HIGHEST=105,
+    R_PPC64_DTPREL16_HIGHESTA=106,
+    R_PPC64_TLSGD=107,
+    R_PPC64_TLSLD=108,
+    R_PPC64_TOCSAVE=109,
+    R_PPC64_ADDR16_HIGH=110,
+    R_PPC64_ADDR16_HIGHA=111,
+    R_PPC64_TPREL16_HIGH=112,
+    R_PPC64_TPREL16_HIGHA=113,
+    R_PPC64_DTPREL16_HIGH=114,
+    R_PPC64_DTPREL16_HIGHA=115,
+    R_PPC64_REL24_NOTOC=116,
+    R_PPC64_ADDR64_LOCAL=117,
+    R_PPC64_IRELATIVE=248,
+    R_PPC64_REL16=249,
+    R_PPC64_REL16_LO=250,
+    R_PPC64_REL16_HI=251,
+    R_PPC64_REL16_HA=252,
+    R_PPC64_GNU_VTINHERIT=253,
+    R_PPC64_GNU_VTENTRY=254,
+)
index 427a56f41856af9f4568dac2a3913f4b9f84eb0d..8ca4ca1bc4e74350ba4eb69d3ef78a830eff5c9f 100644 (file)
@@ -13,7 +13,8 @@ from ..common.utils import elf_assert, struct_parse
 from .sections import Section
 from .enums import (
     ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, ENUM_RELOC_TYPE_MIPS,
-    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_D_TAG)
+    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
+    ENUM_D_TAG)
 
 
 class Relocation(object):
@@ -175,6 +176,8 @@ class RelocationHandler(object):
             recipe = self._RELOCATION_RECIPES_ARM.get(reloc_type, None)
         elif self.elffile.get_machine_arch() == 'AArch64':
             recipe = self._RELOCATION_RECIPES_AARCH64.get(reloc_type, None)
+        elif self.elffile.get_machine_arch() == '64-bit PowerPC':
+            recipe = self._RELOCATION_RECIPES_PPC64.get(reloc_type, None)
 
         if recipe is None:
             raise ELFRelocationError(
@@ -269,6 +272,15 @@ class RelocationHandler(object):
             calc_func=_reloc_calc_sym_plus_value),
     }
 
+    _RELOCATION_RECIPES_PPC64 = {
+        ENUM_RELOC_TYPE_PPC64['R_PPC64_ADDR32']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
+        ENUM_RELOC_TYPE_PPC64['R_PPC64_REL32']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend_pcrel),
+        ENUM_RELOC_TYPE_PPC64['R_PPC64_ADDR64']: _RELOCATION_RECIPE_TYPE(
+            bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
+    }
+
     _RELOCATION_RECIPES_X86 = {
         ENUM_RELOC_TYPE_i386['R_386_NONE']: _RELOCATION_RECIPE_TYPE(
             bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
index 0c6a8090ce713e25a09318247fd20445038c950d..ee4beac88d8de0a306f0df6abf2f7d724016519c 100644 (file)
@@ -289,7 +289,10 @@ class ELFStructs(object):
         # st_other is hierarchical. To access the visibility,
         # use container['st_other']['visibility']
         st_other_struct = BitStruct('st_other',
-            Padding(5),
+            # https://openpowerfoundation.org/wp-content/uploads/2016/03/ABI64BitOpenPOWERv1.1_16July2015_pub4.pdf
+            # See 3.4.1 Symbol Values.
+            Enum(BitField('local', 3), **ENUM_ST_LOCAL),
+            Padding(2),
             Enum(BitField('visibility', 3), **ENUM_ST_VISIBILITY))
         if self.elfclass == 32:
             self.Elf_Sym = Struct('Elf_Sym',
index c298aa28466f2f0e9e61be15eb45f152f274f9de..249d99a5d976d791606c1afa1798c6fd0348d526 100755 (executable)
@@ -48,7 +48,7 @@ from elftools.elf.descriptions import (
     describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
     describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
     describe_dt_flags, describe_dt_flags_1, describe_ver_flags, describe_note,
-    describe_attr_tag_arm
+    describe_attr_tag_arm, describe_symbol_other
     )
 from elftools.elf.constants import E_FLAGS
 from elftools.elf.constants import E_FLAGS_MASKS
@@ -173,6 +173,10 @@ class ReadElf(object):
             else:
                 description += ', <unrecognized EABI>'
 
+        elif self.elffile['e_machine'] == 'EM_PPC64':
+            if flags & E_FLAGS.EF_PPC64_ABI_V2:
+                description += ', abiv2'
+
         elif self.elffile['e_machine'] == "EM_MIPS":
             if flags & E_FLAGS.EF_MIPS_NOREORDER:
                 description += ", noreorder"
@@ -422,7 +426,7 @@ class ReadElf(object):
                     "%5d" % symbol['st_size'] if symbol['st_size'] < 100000 else hex(symbol['st_size']),
                     describe_symbol_type(symbol['st_info']['type']),
                     describe_symbol_bind(symbol['st_info']['bind']),
-                    describe_symbol_visibility(symbol['st_other']['visibility']),
+                    describe_symbol_other(symbol['st_other']),
                     describe_symbol_shndx(self._get_symbol_shndx(symbol,
                                                                  nsym,
                                                                  section_index)),
@@ -1143,7 +1147,7 @@ class ReadElf(object):
                     # readelf doesn't print the state after end_sequence
                     # instructions. I think it's a bug but to be compatible
                     # I don't print them too.
-                    if lineprogram['version'] < 4:
+                    if lineprogram['version'] < 4 or self.elffile['e_machine'] == 'EM_PPC64':
                         self._emitline('%-35s  %11d  %18s' % (
                             bytes2str(lineprogram['file_entry'][state.file - 1].name),
                             state.line,
diff --git a/test/testfiles_for_readelf/powerpc64-relocs-le.o.elf b/test/testfiles_for_readelf/powerpc64-relocs-le.o.elf
new file mode 100644 (file)
index 0000000..9d67c1f
Binary files /dev/null and b/test/testfiles_for_readelf/powerpc64-relocs-le.o.elf differ
diff --git a/test/testfiles_for_readelf/powerpc64-relocs.c b/test/testfiles_for_readelf/powerpc64-relocs.c
new file mode 100644 (file)
index 0000000..fe5c3e8
--- /dev/null
@@ -0,0 +1,16 @@
+/* This source was compiled for ppc64le.
+   clang --target=powerpc64le -c -o powerpc64-relocs-le.o.elf powerpc64-relocs.c -g
+*/
+
+extern struct {
+  int i, j;
+} data;
+
+extern int bar (void);
+
+int
+foo (int a)
+{
+  data.i += a;
+  data.j -= bar();
+}