Skip to content

Commit

Permalink
[lld][ARM][NFCI][1/3]Big Endian support - Removing assumptions
Browse files Browse the repository at this point in the history
Change:
 - Replacing the memcpy that assume little endian with the endian-aware write.

Shouldn't affect the output for now, just a prerequisite for the next patches.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D140201
  • Loading branch information
simpal01 committed Feb 15, 2023
1 parent 5bb8ead commit 674f094
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 125 deletions.
30 changes: 13 additions & 17 deletions lld/ELF/Arch/ARM.cpp
Expand Up @@ -15,6 +15,7 @@

using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::support;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
Expand Down Expand Up @@ -194,16 +195,14 @@ void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
// Long form PLT Header that does not have any restrictions on the displacement
// of the .plt from the .got.plt.
static void writePltHeaderLong(uint8_t *buf) {
const uint8_t pltData[] = {
0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
0xd4, 0xd4, 0xd4, 0xd4};
memcpy(buf, pltData, sizeof(pltData));
write32(buf + 0, 0xe52de004); // str lr, [sp,#-4]!
write32(buf + 4, 0xe59fe004); // ldr lr, L2
write32(buf + 8, 0xe08fe00e); // L1: add lr, pc, lr
write32(buf + 12, 0xe5bef008); // ldr pc, [lr, #8]
write32(buf + 16, 0x00000000); // L2: .word &(.got.plt) - L1 - 8
write32(buf + 20, 0xd4d4d4d4); // Pad to 32-byte boundary
write32(buf + 24, 0xd4d4d4d4); // Pad to 32-byte boundary
write32(buf + 28, 0xd4d4d4d4);
uint64_t gotPlt = in.gotPlt->getVA();
uint64_t l1 = in.plt->getVA() + 8;
write32le(buf + 16, gotPlt - l1 - 8);
Expand Down Expand Up @@ -248,13 +247,10 @@ void ARM::addPltHeaderSymbols(InputSection &isec) const {
// of the .plt from the .got.plt.
static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr,
uint64_t pltEntryAddr) {
const uint8_t pltData[] = {
0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.got.plt) - L1 - 8
};
memcpy(buf, pltData, sizeof(pltData));
write32(buf + 0, 0xe59fc004); // ldr ip, L2
write32(buf + 4, 0xe08cc00f); // L1: add ip, ip, pc
write32(buf + 8, 0xe59cf000); // ldr pc, [ip]
write32(buf + 12, 0x00000000); // L2: .word Offset(&(.got.plt) - L1 - 8
uint64_t l1 = pltEntryAddr + 4;
write32le(buf + 12, gotPltEntryAddr - l1 - 8);
}
Expand Down
172 changes: 64 additions & 108 deletions lld/ELF/Thunks.cpp
Expand Up @@ -554,10 +554,7 @@ void ARMThunk::writeTo(uint8_t *buf) {
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA();
int64_t offset = s - p - 8;
const uint8_t data[] = {
0x00, 0x00, 0x00, 0xea, // b S
};
memcpy(buf, data, sizeof(data));
write32(buf, 0xea000000); // b S
target->relocateNoSym(buf, R_ARM_JUMP24, offset);
}

Expand Down Expand Up @@ -600,10 +597,7 @@ void ThumbThunk::writeTo(uint8_t *buf) {
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA();
int64_t offset = s - p - 4;
const uint8_t data[] = {
0x00, 0xf0, 0x00, 0xb0, // b.w S
};
memcpy(buf, data, sizeof(data));
write32(buf, 0xb000f000); // b.w S
target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
}

Expand All @@ -618,13 +612,10 @@ bool ThumbThunk::isCompatibleWith(const InputSection &isec,
}

void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
write32(buf + 0, 0xe300c000); // movw ip,:lower16:S
write32(buf + 4, 0xe340c000); // movt ip,:upper16:S
write32(buf + 8, 0xe12fff1c); // bx ip
uint64_t s = getARMThunkDestVA(destination);
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
}
Expand All @@ -636,13 +627,12 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
0x60, 0x47, // bx ip
};
write16(buf + 0, 0xf240); // movw ip, :lower16:S
write16(buf + 2, 0x0c00);
write16(buf + 4, 0xf2c0); // movt ip, :upper16:S
write16(buf + 6, 0x0c00);
write16(buf + 8, 0x4760); // bx ip
uint64_t s = getARMThunkDestVA(destination);
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
}
Expand All @@ -654,16 +644,13 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
}

void ARMV7PILongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
write32(buf + 0, 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
write32(buf + 4, 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
write32(buf + 8, 0xe08cc00f); // L1: add ip, ip, pc
write32(buf + 12, 0xe12fff1c); // bx ip
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA();
int64_t offset = s - p - 16;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
}
Expand All @@ -675,16 +662,15 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
0xfc, 0x44, // L1: add ip, pc
0x60, 0x47, // bx ip
};
write16(buf + 0, 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
write16(buf + 2, 0x7cf4);
write16(buf + 4, 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
write16(buf + 6, 0x0c00);
write16(buf + 8, 0x44fc); // L1: add ip, pc
write16(buf + 10, 0x4760); // bx ip
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
int64_t offset = s - p - 12;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
}
Expand All @@ -700,15 +686,12 @@ void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
// only register we can corrupt is r12 we must instead spill a low register
// to the stack to use as a scratch register. We push r1 even though we
// don't need to get some space to use for the return address.
const uint8_t data[] = {
0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
0x01, 0x48, // ldr r0, [pc, #4] ; L1
0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
0x00, 0x00, 0x00, 0x00 // L1: .word S
};
write16(buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
write16(buf + 2, 0x4801); // ldr r0, [pc, #4] ; L1
write16(buf + 4, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
write16(buf + 6, 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
write32(buf + 8, 0x00000000); // L1: .word S
uint64_t s = getARMThunkDestVA(destination);
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
}

Expand All @@ -723,18 +706,15 @@ void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
// Most Thumb instructions cannot access the high registers r8 - r15. As the
// only register we can corrupt is ip (r12) we must instead spill a low
// register to the stack to use as a scratch register.
const uint8_t data[] = {
0x01, 0xb4, // P: push {r0} ; Obtain scratch register
0x02, 0x48, // ldr r0, [pc, #8] ; L2
0x84, 0x46, // mov ip, r0 ; high to low register
0x01, 0xbc, // pop {r0} ; restore scratch register
0xe7, 0x44, // L1: add pc, ip ; transfer control
0xc0, 0x46, // nop ; pad to 4-byte boundary
0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
};
write16(buf + 0, 0xb401); // P: push {r0} ; Obtain scratch register
write16(buf + 2, 0x4802); // ldr r0, [pc, #8] ; L2
write16(buf + 4, 0x4684); // mov ip, r0 ; high to low register
write16(buf + 6, 0xbc01); // pop {r0} ; restore scratch register
write16(buf + 8, 0x44e7); // L1: add pc, ip ; transfer control
write16(buf + 10, 0x46c0); // nop ; pad to 4-byte boundary
write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
}

Expand All @@ -746,11 +726,8 @@ void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
}

void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
0x00, 0x00, 0x00, 0x00, // L1: .word S
};
memcpy(buf, data, sizeof(data));
write32(buf + 0, 0xe51ff004); // ldr pc, [pc,#-4] ; L1
write32(buf + 4, 0x00000000); // L1: .word S
target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
}

Expand All @@ -762,12 +739,9 @@ void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
}

void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
0x1c, 0xff, 0x2f, 0xe1, // bx r12
0x00, 0x00, 0x00, 0x00, // L1: .word S
};
memcpy(buf, data, sizeof(data));
write32(buf + 0, 0xe59fc000); // ldr r12, [pc] ; L1
write32(buf + 4, 0xe12fff1c); // bx r12
write32(buf + 8, 0x00000000); // L1: .word S
target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
}

Expand All @@ -779,13 +753,10 @@ void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x78, 0x47, // bx pc
0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] ; L1
0x00, 0x00, 0x00, 0x00, // L1: .word S
};
memcpy(buf, data, sizeof(data));
write16(buf + 0, 0x4778); // bx pc
write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
write32(buf + 4, 0xe51ff004); // ldr pc, [pc, #-4] ; L1
write32(buf + 8, 0x00000000); // L1: .word S
target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
}

Expand All @@ -798,14 +769,11 @@ void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x78, 0x47, // bx pc
0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
0x1c, 0xff, 0x2f, 0xe1, // bx r12
0x00, 0x00, 0x00, 0x00, // L1: .word S
};
memcpy(buf, data, sizeof(data));
write16(buf + 0, 0x4778); // bx pc
write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
write32(buf + 4, 0xe59fc000); // ldr r12, [pc] ; L1
write32(buf + 8, 0xe12fff1c); // bx r12
write32(buf + 12, 0x00000000); // L1: .word S
target->relocateNoSym(buf + 12, R_ARM_ABS32, getARMThunkDestVA(destination));
}

Expand All @@ -818,15 +786,12 @@ void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
}

void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
0x1c, 0xff, 0x2f, 0xe1, // bx ip
0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
};
write32(buf + 0, 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
write32(buf + 4, 0xe08fc00c); // L1: add ip, pc, ip
write32(buf + 8, 0xe12fff1c); // bx ip
write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
}

Expand All @@ -838,14 +803,11 @@ void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
}

void ARMV4PILongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x00, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc] ; L2
0x0c, 0xf0, 0x8f, 0xe0, // L1: add pc, pc, r12
0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
};
write32(buf + 0, 0xe59fc000); // P: ldr ip, [pc] ; L2
write32(buf + 4, 0xe08ff00c); // L1: add pc, pc, r12
write32(buf + 8, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12);
}

Expand All @@ -857,16 +819,13 @@ void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x78, 0x47, // P: bx pc
0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L2
0x0f, 0xf0, 0x8c, 0xe0, // L1: add pc, r12, pc
0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
};
write16(buf + 0, 0x4778); // P: bx pc
write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
write32(buf + 4, 0xe59fc000); // ldr r12, [pc] ; L2
write32(buf + 8, 0xe08cf00f); // L1: add pc, r12, pc
write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16);
}

Expand All @@ -879,17 +838,14 @@ void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
}

void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x78, 0x47, // P: bx pc
0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
0x04, 0xc0, 0x9f, 0xe5, // ldr ip, [pc,#4] ; L2
0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
0x1c, 0xff, 0x2f, 0xe1, // bx ip
0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
};
write16(buf + 0, 0x4778); // P: bx pc
write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
write32(buf + 4, 0xe59fc004); // ldr ip, [pc,#4] ; L2
write32(buf + 8, 0xe08fc00c); // L1: add ip, pc, ip
write32(buf + 12, 0xe12fff1c); // bx ip
write32(buf + 16, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16);
}

Expand Down

0 comments on commit 674f094

Please sign in to comment.