Bug 898998 - Turn BL into BLX when doing thumb call relocations and the target is ARM. r=nfroyd

This commit is contained in:
Mike Hommey 2013-07-30 08:57:28 +09:00
parent c8693625db
commit 7c008ee6a3
2 changed files with 23 additions and 3 deletions

View File

@ -240,9 +240,26 @@ private:
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;
@ -256,7 +273,7 @@ private:
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);
}
};

View File

@ -22,7 +22,7 @@ extern __attribute__((visibility("hidden"))) void original_init(int argc, char *
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;
@ -35,4 +35,7 @@ void init(int argc, char **argv, char **env)
#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;
}