using namespace llvm;
using namespace llvm::support::endian;
+using namespace llvm::support;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
// 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);
// 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);
}
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);
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
// 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);
}
// 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);
}
}
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));
}
}
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));
}
}
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));
}
}
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));
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}