Bug 898998 - Turn BL into BLX when doing thumb call relocations and the target is ARM. r=nfroyd
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 30 Jul 2013 08:57:28 +0900
changeset 152763 09fa1683d16a33f08562545002245bf45527b219
parent 152762 7506c6ee2e8b25f5893dc23e1b392ec5828ba545
child 152764 1f59dc8474a5dd5fe4a48efdb35111d92d4bbe83
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd
bugs898998
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 898998 - Turn BL into BLX when doing thumb call relocations and the target is ARM. r=nfroyd
build/unix/elfhack/elfhack.cpp
build/unix/elfhack/inject.c
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -235,33 +235,50 @@ private:
                ARM Architecture Reference Manual ARMĀ® v7-A and ARMĀ® v7-R edition, A8.6.16
                We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl.
                We don't care about sign_extend because the only case where this is
                going to be used only jumps forward. */
             Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr);
             unsigned int word0 = addend & 0xffff,
                          word1 = addend >> 16;
 
-            if (((word0 & 0xf800) != 0xf000) || ((word1 & 0x9000) != 0x9000))
+            /* Encoding T4 of B.W is 10x1 ; Encoding T1 of BL is 11x1. */
+            unsigned int type = (word1 & 0xd000) >> 12;
+            if (((word0 & 0xf800) != 0xf000) || ((type & 0x9) != 0x9))
                 throw std::runtime_error("R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for B.W <label> and BL <label>");
 
+            /* When the target address points to ARM code, switch a BL to a
+             * BLX. This however can't be done with a B.W without adding a
+             * trampoline, which is not supported as of now. */
+            if ((addr & 0x1) == 0) {
+                if (type == 0x9)
+                    throw std::runtime_error("R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for BL <label> when label points to ARM code");
+                /* The address of the target is always relative to a 4-bytes
+                 * aligned address, so if the address of the BL instruction is
+                 * not 4-bytes aligned, adjust for it. */
+                if ((base_addr + offset) & 0x2)
+                    tmp += 2;
+                /* Encoding T2 of BLX is 11x0. */
+                type = 0xc;
+            }
+
             unsigned int s = (word0 & (1 << 10)) >> 10;
             unsigned int j1 = (word1 & (1 << 13)) >> 13;
             unsigned int j2 = (word1 & (1 << 11)) >> 11;
             unsigned int i1 = j1 ^ s ? 0 : 1;
             unsigned int i2 = j2 ^ s ? 0 : 1;
 
             tmp += ((s << 24) | (i1 << 23) | (i2 << 22) | ((word0 & 0x3ff) << 12) | ((word1 & 0x7ff) << 1));
 
             s = (tmp & (1 << 24)) >> 24;
             j1 = ((tmp & (1 << 23)) >> 23) ^ !s;
             j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
 
             return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) |
-                   ((word1 & 0xd000) << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
+                   (type << 28) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
         }
     };
 
     class gotoff_relocation {
     public:
         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
                               Elf32_Word addend, unsigned int addr)
         {
--- a/build/unix/elfhack/inject.c
+++ b/build/unix/elfhack/inject.c
@@ -17,22 +17,25 @@
 #define Elf_Addr Elf64_Addr
 #endif
 
 extern __attribute__((visibility("hidden"))) void original_init(int argc, char **argv, char **env);
 
 extern __attribute__((visibility("hidden"))) Elf32_Rel relhack[];
 extern __attribute__((visibility("hidden"))) Elf_Ehdr elf_header;
 
-void init(int argc, char **argv, char **env)
+int init(int argc, char **argv, char **env)
 {
     Elf32_Rel *rel;
     Elf_Addr *ptr, *start;
     for (rel = relhack; rel->r_offset; rel++) {
         start = (Elf_Addr *)((intptr_t)&elf_header + rel->r_offset);
         for (ptr = start; ptr < &start[rel->r_info]; ptr++)
             *ptr += (intptr_t)&elf_header;
     }
 
 #ifndef NOINIT
     original_init(argc, argv, env);
 #endif
+    // Ensure there is no tail-call optimization, avoiding the use of the
+    // B.W instruction in Thumb for the call above.
+    return 0;
 }