Call relocation for ARM V3 (#194)
authorDmitry Koltunov <koltunov@ispras.ru>
Wed, 5 Sep 2018 12:25:28 +0000 (15:25 +0300)
committerEli Bendersky <eliben@users.noreply.github.com>
Wed, 5 Sep 2018 12:25:28 +0000 (05:25 -0700)
* Add support for 'R_ARM_CALL' relocation type

* Add test script and test files to verify support for 'R_ARM_CALL'

Signed-off-by: Koltunov Dmitry <koltunov@ispras.ru>
elftools/elf/relocation.py
test/run_arm_reloc_call_test.py [new file with mode: 0755]
test/testfiles_for_unittests/reloc_simple_arm_llvm.o [new file with mode: 0644]
test/testfiles_for_unittests/simple.c [new file with mode: 0644]
test/testfiles_for_unittests/simple_arm_llvm.elf [new file with mode: 0755]

index 6f2c4b4e979ab84e93402a3a4dd3f92fc7a24587..59b67500b7c3715502f3466fc3a5ef256aa44c89 100644 (file)
@@ -219,10 +219,16 @@ class RelocationHandler(object):
     def _reloc_calc_sym_plus_addend_pcrel(value, sym_value, offset, addend=0):
         return sym_value + addend - offset
 
+    def _arm_reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0):
+        return sym_value / 4 + value - offset / 4
+
     _RELOCATION_RECIPES_ARM = {
         ENUM_RELOC_TYPE_ARM['R_ARM_ABS32']: _RELOCATION_RECIPE_TYPE(
             bytesize=4, has_addend=False,
             calc_func=_reloc_calc_sym_plus_value),
+        ENUM_RELOC_TYPE_ARM['R_ARM_CALL']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=False,
+            calc_func=_arm_reloc_calc_sym_plus_value_pcrel),
     }
 
     # https://dmz-portal.mips.com/wiki/MIPS_relocation_types
diff --git a/test/run_arm_reloc_call_test.py b/test/run_arm_reloc_call_test.py
new file mode 100755 (executable)
index 0000000..261949d
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#-------------------------------------------------------------------------------
+# test/run_arm_reloc_call_test.py
+#
+# Test 'R_ARM_CALL' relocation type support.
+# Compare the '.text' section data of ELF file that relocated by elftools
+# and ELF file that relocated by linker.
+#
+# Dmitry Koltunov (koltunov@ispras.ru)
+#-------------------------------------------------------------------------------
+from os.path import (
+    join,
+    dirname
+)
+from sys import (
+    exit
+)
+
+from elftools.common.py3compat import (
+    BytesIO
+)
+from elftools.elf.elffile import (
+    ELFFile
+)
+from elftools.elf.relocation import (
+    RelocationHandler
+)
+
+
+def do_relocation(rel_elf):
+    data = rel_elf.get_section_by_name('.text').data()
+    rh = RelocationHandler(rel_elf)
+
+    stream = BytesIO()
+    stream.write(data)
+
+    rel = rel_elf.get_section_by_name('.rel.text')
+    rh.apply_section_relocations(stream, rel)
+
+    stream.seek(0)
+    data = stream.readlines()
+
+    return data
+
+
+def main():
+    test_dir = join(dirname(__file__) or '.', 'testfiles_for_unittests')
+    with open(join(test_dir, 'reloc_simple_arm_llvm.o'), 'rb') as rel_f, \
+            open(join(test_dir, 'simple_arm_llvm.elf'), 'rb') as f:
+        rel_elf = ELFFile(rel_f)
+        elf = ELFFile(f)
+
+        # Comparison of '.text' section data
+        if do_relocation(rel_elf).pop() != elf.get_section_by_name('.text').data():
+            print 'FAIL'
+            return 1
+        print 'OK'
+        return 0
+
+
+if __name__ == '__main__':
+    exit(main())
diff --git a/test/testfiles_for_unittests/reloc_simple_arm_llvm.o b/test/testfiles_for_unittests/reloc_simple_arm_llvm.o
new file mode 100644 (file)
index 0000000..a1bfbaa
Binary files /dev/null and b/test/testfiles_for_unittests/reloc_simple_arm_llvm.o differ
diff --git a/test/testfiles_for_unittests/simple.c b/test/testfiles_for_unittests/simple.c
new file mode 100644 (file)
index 0000000..4ea1c67
--- /dev/null
@@ -0,0 +1,41 @@
+/* Generated by compiling with any LLVM version and
+** with any GNU Arm Embedded Toolchain version.
+** LLVM 3.8.0/5.0.0 and GNU Arm Embedded Toolchain 2.26 is fine.
+**
+** clang -O0 --target=arm-none-eabi -emit-llvm -c simple.c -o simple.bc
+** llc -O0 -march=arm -filetype=obj simple.bc -o reloc_simple_arm_llvm.o
+** arm-none-eabi-ld -e main reloc_simple_arm_llvm.o -o simple_arm_llvm.elf
+**
+** reloc_simple_arm_llvm.o is ELF file that needs call relocation.
+**
+** simple_arm_llvm.elf is a relocated ELF file.
+*/
+
+int add(int a, int b) {
+    return a + b;
+}
+
+int sub(int a, int b) {
+    return a - b;
+}
+
+int mul(int a, int b) {
+    return a * b;
+}
+
+void triple(int a, int b) {
+    add(a, b);
+    sub(a, b);
+    mul(a, b);
+}
+
+int main(void) {
+    int a = 0xABCD, b = 0x1234;
+
+    add(a, b);
+    sub(a, b);
+    mul(a, b);
+    triple(a, b);
+
+    return 0;
+}
diff --git a/test/testfiles_for_unittests/simple_arm_llvm.elf b/test/testfiles_for_unittests/simple_arm_llvm.elf
new file mode 100755 (executable)
index 0000000..f1cfbb8
Binary files /dev/null and b/test/testfiles_for_unittests/simple_arm_llvm.elf differ