Bug 1747783 - Add support for aarch64 to elfhack. r=gsvelto

Differential Revision: https://phabricator.services.mozilla.com/D134764
This commit is contained in:
Mike Hommey 2021-12-30 20:52:55 +00:00
parent 837162a71b
commit 523b1551b3
2 changed files with 93 additions and 9 deletions

View File

@ -109,6 +109,9 @@ class ElfRelHackCode_Section : public ElfSection {
case EM_ARM: case EM_ARM:
file += "arm"; file += "arm";
break; break;
case EM_AARCH64:
file += "aarch64";
break;
default: default:
throw std::runtime_error("unsupported architecture"); throw std::runtime_error("unsupported architecture");
} }
@ -269,10 +272,13 @@ class ElfRelHackCode_Section : public ElfSection {
} }
} }
// TODO: sort out which non-aarch64 relocation types should be using
// `value` (even though in practice it's either 0 or the same as addend)
class pc32_relocation { class pc32_relocation {
public: public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr) { Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
return addr + addend - offset - base_addr; return addr + addend - offset - base_addr;
} }
}; };
@ -280,7 +286,8 @@ class ElfRelHackCode_Section : public ElfSection {
class arm_plt32_relocation { class arm_plt32_relocation {
public: public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr) { Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
// We don't care about sign_extend because the only case where this is // We don't care about sign_extend because the only case where this is
// going to be used only jumps forward. // going to be used only jumps forward.
Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr) >> 2; Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr) >> 2;
@ -292,7 +299,8 @@ class ElfRelHackCode_Section : public ElfSection {
class arm_thm_jump24_relocation { class arm_thm_jump24_relocation {
public: public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr) { Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
/* Follows description of b.w and bl instructions as per /* Follows description of b.w and bl instructions as per
ARM Architecture Reference Manual ARM® v7-A and ARM® v7-R edition, 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. A8.6.16 We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl.
@ -345,18 +353,66 @@ class ElfRelHackCode_Section : public ElfSection {
class gotoff_relocation { class gotoff_relocation {
public: public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr) { Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
return addr + addend; return addr + addend;
} }
}; };
template <int start, int end>
class abs_lo12_nc_relocation {
public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
// Fill the bits [end:start] of the immediate value in an ADD, LDR or STR
// instruction, at bits [21:10].
// per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
// profile C5.6.4, C5.6.83 or C5.6.178 and ELF for the ARM® 64-bit
// Architecture (AArch64) 4.6.6, Table 4-9.
Elf64_Word mask = (1 << (end + 1)) - 1;
return value | (((((addr + addend) & mask) >> start) & 0xfff) << 10);
}
};
class adr_prel_pg_hi21_relocation {
public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
// Fill the bits [32:12] of the immediate value in a ADRP instruction,
// at bits [23:5]+[30:29].
// per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
// profile C5.6.10 and ELF for the ARM® 64-bit Architecture
// (AArch64) 4.6.6, Table 4-9.
Elf64_Word imm = ((addr + addend) >> 12) - ((base_addr + offset) >> 12);
Elf64_Word immLo = (imm & 0x3) << 29;
Elf64_Word immHi = (imm & 0x1ffffc) << 3;
return value & 0x9f00001f | immLo | immHi;
}
};
class call26_relocation {
public:
Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
Elf64_Sxword addend, unsigned int addr,
Elf64_Word value) {
// Fill the bits [27:2] of the immediate value in a BL instruction,
// at bits [25:0].
// per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
// profile C5.6.26 and ELF for the ARM® 64-bit Architecture
// (AArch64) 4.6.6, Table 4-10.
return value | (((addr + addend - offset - base_addr) & 0x0ffffffc) >> 2);
}
};
template <class relocation_type> template <class relocation_type>
void apply_relocation(ElfSection* the_code, char* base, Elf_Rel* r, void apply_relocation(ElfSection* the_code, char* base, Elf_Rel* r,
unsigned int addr) { unsigned int addr) {
relocation_type relocation; relocation_type relocation;
Elf32_Addr value; Elf32_Addr value;
memcpy(&value, base + r->r_offset, 4); memcpy(&value, base + r->r_offset, 4);
value = relocation(the_code->getAddr(), r->r_offset, value, addr); value = relocation(the_code->getAddr(), r->r_offset, value, addr, value);
memcpy(base + r->r_offset, &value, 4); memcpy(base + r->r_offset, &value, 4);
} }
@ -364,9 +420,11 @@ class ElfRelHackCode_Section : public ElfSection {
void apply_relocation(ElfSection* the_code, char* base, Elf_Rela* r, void apply_relocation(ElfSection* the_code, char* base, Elf_Rela* r,
unsigned int addr) { unsigned int addr) {
relocation_type relocation; relocation_type relocation;
Elf32_Addr value = Elf64_Word value;
relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr); memcpy(&value, base + r->r_offset, 4);
memcpy(base + r->r_offset, &value, 4); Elf32_Addr new_value =
relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr, value);
memcpy(base + r->r_offset, &new_value, 4);
} }
template <typename Rel_Type> template <typename Rel_Type>
@ -429,6 +487,7 @@ class ElfRelHackCode_Section : public ElfSection {
case REL(386, GOTPC): case REL(386, GOTPC):
case REL(ARM, GOTPC): case REL(ARM, GOTPC):
case REL(ARM, REL32): case REL(ARM, REL32):
case REL(AARCH64, PREL32):
apply_relocation<pc32_relocation>(the_code, buf, &*r, addr); apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
break; break;
case REL(ARM, CALL): case REL(ARM, CALL):
@ -444,6 +503,25 @@ class ElfRelHackCode_Section : public ElfSection {
case REL(ARM, GOTOFF): case REL(ARM, GOTOFF):
apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr); apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr);
break; break;
case REL(AARCH64, ADD_ABS_LO12_NC):
apply_relocation<abs_lo12_nc_relocation<0, 11>>(the_code, buf, &*r,
addr);
break;
case REL(AARCH64, ADR_PREL_PG_HI21):
apply_relocation<adr_prel_pg_hi21_relocation>(the_code, buf, &*r,
addr);
break;
case REL(AARCH64, LDST32_ABS_LO12_NC):
apply_relocation<abs_lo12_nc_relocation<2, 11>>(the_code, buf, &*r,
addr);
break;
case REL(AARCH64, LDST64_ABS_LO12_NC):
apply_relocation<abs_lo12_nc_relocation<3, 11>>(the_code, buf, &*r,
addr);
break;
case REL(AARCH64, CALL26):
apply_relocation<call26_relocation>(the_code, buf, &*r, addr);
break;
case REL(ARM, V4BX): case REL(ARM, V4BX):
// Ignore R_ARM_V4BX relocations // Ignore R_ARM_V4BX relocations
break; break;
@ -1233,6 +1311,12 @@ void do_file(const char* name, bool backup = false, bool force = false) {
exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32, exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32,
force); force);
break; break;
case EM_AARCH64:
exit = do_relocation_section<Elf_Rela>(&elf, R_AARCH64_RELATIVE,
R_AARCH64_ABS64, force);
break;
default:
throw std::runtime_error("unsupported architecture");
} }
if (exit == 0) { if (exit == 0) {
if (!force && (elf.getSize() >= size)) { if (!force && (elf.getSize() >= size)) {

View File

@ -1256,7 +1256,7 @@ with only_when("--enable-compile-environment"):
return ( return (
target.kernel == "Linux" target.kernel == "Linux"
and host.kernel == "Linux" and host.kernel == "Linux"
and target.cpu in ("arm", "x86", "x86_64") and target.cpu in ("arm", "aarch64", "x86", "x86_64")
) )
@depends("--enable-release", enable_linker) @depends("--enable-release", enable_linker)