[Elf/arm] Thumb indicator bit only for STT_FUNC
authorMoritz Angermann <moritz.angermann@gmail.com>
Tue, 11 Apr 2017 01:39:19 +0000 (21:39 -0400)
committerBen Gamari <ben@smart-cactus.org>
Tue, 11 Apr 2017 01:39:20 +0000 (21:39 -0400)
Reviewers: rwbarton, bgamari, austin, erikd, simonmar, trofi

Reviewed By: trofi

Subscribers: trofi, thomie

Differential Revision: https://phabricator.haskell.org/D3438

rts/linker/Elf.c

index 77107a7..174fc47 100644 (file)
@@ -992,15 +992,37 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
          IF_DEBUG(linker,debugBelch( "`%s' resolves to %p\n", symbol, (void*)S ));
 
 #ifdef arm_HOST_ARCH
-         // Thumb instructions have bit 0 of symbol's st_value set
-         is_target_thm = S & 0x1;
-
-         T = sym.st_info & STT_FUNC && is_target_thm;
-
-         // Make sure we clear bit 0. Strictly speaking we should have done
-         // this to st_value above but I believe alignment requirements should
-         // ensure that no instructions start on an odd address
-         S &= ~1;
+          /*
+           * 4.5.3 Symbol Values
+           *
+           * In addition to the normal rules for symbol values the following
+           * rules shall also apply to symbols of type STT_FUNC:
+           * - If the symbol addresses an ARM instruction, its value is the
+           *   address of the instruction (in a relocatable object, the
+           *   offset of the instruction from the start of the section
+           *   containing it).
+           * - If the symbol addresses a Thumb instruction, its value is the
+           *   address of the instruction with bit zero set (in a relocatable
+           *   object, the section offset with bit zero set).
+           * - For the purposes of relocation the value used shall be the
+           *   address of the instruction (st_value & ~1).
+           *
+           *  Note: This allows a linker to distinguish ARM and Thumb code
+           *        symbols without having to refer to the map. An ARM symbol
+           *        will always have an even value, while a Thumb symbol will
+           *        always have an odd value. However, a linker should strip
+           *        the discriminating bit from the value before using it for
+           *        relocation.
+           *
+           * (source: ELF for the ARM Architecture
+           *          ARM IHI 0044F, current through ABI release 2.10
+           *          24th November 2015)
+           */
+          if(ELF_ST_TYPE(sym.st_info) == STT_FUNC) {
+              is_target_thm = S & 0x1;
+              T = is_target_thm;
+              S &= ~1;
+          }
 #endif
       }