mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-14 16:33:28 +00:00
[RuntimeDyld][MachO][AArch64] Add a helper function for encoding addends in instructions.
Factor out the addend encoding into a helper function and simplify the processRelocationRef. Also add a few simple rtdyld tests. More tests to come once GOTs can be tested too. Related to <rdar://problem/17768539> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213689 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6f2f090b06
commit
04e8cc79cd
@ -118,6 +118,109 @@ public:
|
|||||||
return Addend;
|
return Addend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the addend encoded in the instruction.
|
||||||
|
void encodeAddend(uint8_t *LocalAddress, uint32_t RelType,
|
||||||
|
int64_t Addend) const {
|
||||||
|
// Verify that the relocation has the correct alignment.
|
||||||
|
switch (RelType) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unsupported relocation type!");
|
||||||
|
case MachO::ARM64_RELOC_UNSIGNED:
|
||||||
|
llvm_unreachable("Invalid relocation type for instruction.");
|
||||||
|
case MachO::ARM64_RELOC_BRANCH26:
|
||||||
|
case MachO::ARM64_RELOC_PAGE21:
|
||||||
|
case MachO::ARM64_RELOC_PAGEOFF12:
|
||||||
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
||||||
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
||||||
|
assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
|
||||||
|
"Instruction address is not aligned to 4 bytes.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (RelType) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unsupported relocation type!");
|
||||||
|
case MachO::ARM64_RELOC_BRANCH26: {
|
||||||
|
// Verify that the relocation points to the expected branch instruction.
|
||||||
|
uint32_t *p = (uint32_t *)LocalAddress;
|
||||||
|
assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
|
||||||
|
|
||||||
|
// Verify addend value.
|
||||||
|
assert((Addend & 0x3) == 0 && "Branch target is not aligned");
|
||||||
|
assert(isInt<28>(Addend) && "Branch target is out of range.");
|
||||||
|
|
||||||
|
// Encode the addend as 26 bit immediate in the branch instruction.
|
||||||
|
*p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
||||||
|
case MachO::ARM64_RELOC_PAGE21: {
|
||||||
|
// Verify that the relocation points to the expected adrp instruction.
|
||||||
|
uint32_t *p = (uint32_t *)LocalAddress;
|
||||||
|
assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
|
||||||
|
|
||||||
|
// Check that the addend fits into 21 bits (+ 12 lower bits).
|
||||||
|
assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
|
||||||
|
assert(isInt<33>(Addend) && "Invalid page reloc value.");
|
||||||
|
|
||||||
|
// Encode the addend into the instruction.
|
||||||
|
uint32_t ImmLoValue = (uint32_t)(Addend << 17) & 0x60000000;
|
||||||
|
uint32_t ImmHiValue = (uint32_t)(Addend >> 9) & 0x00FFFFE0;
|
||||||
|
*p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
|
||||||
|
// Verify that the relocation points to one of the expected load / store
|
||||||
|
// instructions.
|
||||||
|
uint32_t *p = (uint32_t *)LocalAddress;
|
||||||
|
assert((*p & 0x3B000000) == 0x39000000 &&
|
||||||
|
"Only expected load / store instructions.");
|
||||||
|
} // fall-through
|
||||||
|
case MachO::ARM64_RELOC_PAGEOFF12: {
|
||||||
|
// Verify that the relocation points to one of the expected load / store
|
||||||
|
// or add / sub instructions.
|
||||||
|
uint32_t *p = (uint32_t *)LocalAddress;
|
||||||
|
assert((((*p & 0x3B000000) == 0x39000000) ||
|
||||||
|
((*p & 0x11C00000) == 0x11000000) ) &&
|
||||||
|
"Expected load / store or add/sub instruction.");
|
||||||
|
|
||||||
|
// Check which instruction we are decoding to obtain the implicit shift
|
||||||
|
// factor of the instruction and verify alignment.
|
||||||
|
int ImplicitShift = 0;
|
||||||
|
if ((*p & 0x3B000000) == 0x39000000) { // << load / store
|
||||||
|
// For load / store instructions the size is encoded in bits 31:30.
|
||||||
|
ImplicitShift = ((*p >> 30) & 0x3);
|
||||||
|
switch (ImplicitShift) {
|
||||||
|
case 0:
|
||||||
|
// Check if this a vector op to get the correct shift value.
|
||||||
|
if ((*p & 0x04800000) == 0x04800000) {
|
||||||
|
ImplicitShift = 4;
|
||||||
|
assert(((Addend & 0xF) == 0) &&
|
||||||
|
"128-bit LDR/STR not 16-byte aligned.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Compensate for implicit shift.
|
||||||
|
Addend >>= ImplicitShift;
|
||||||
|
assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
|
||||||
|
|
||||||
|
// Encode the addend into the instruction.
|
||||||
|
*p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
relocation_iterator
|
relocation_iterator
|
||||||
processRelocationRef(unsigned SectionID, relocation_iterator RelI,
|
processRelocationRef(unsigned SectionID, relocation_iterator RelI,
|
||||||
ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
|
ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
|
||||||
@ -196,105 +299,37 @@ public:
|
|||||||
}
|
}
|
||||||
case MachO::ARM64_RELOC_BRANCH26: {
|
case MachO::ARM64_RELOC_BRANCH26: {
|
||||||
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
|
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
|
||||||
// Mask the value into the target address. We know instructions are
|
|
||||||
// 32-bit aligned, so we can do it all at once.
|
|
||||||
uint32_t *p = (uint32_t *)LocalAddress;
|
|
||||||
// Check if the addend is encoded in the instruction.
|
|
||||||
uint32_t EncodedAddend = *p & 0x03FFFFFF;
|
|
||||||
if (EncodedAddend != 0) {
|
|
||||||
if (RE.Addend == 0)
|
|
||||||
llvm_unreachable("branch26 instruction has embedded addend.");
|
|
||||||
else
|
|
||||||
llvm_unreachable("branch26 instruction has embedded addend and"
|
|
||||||
"ARM64_RELOC_ADDEND.");
|
|
||||||
}
|
|
||||||
// Check if branch is in range.
|
// Check if branch is in range.
|
||||||
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
|
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
|
||||||
uint64_t PCRelVal = Value - FinalAddress + RE.Addend;
|
int64_t PCRelVal = Value - FinalAddress + RE.Addend;
|
||||||
assert(isInt<26>(PCRelVal) && "Branch target out of range!");
|
encodeAddend(LocalAddress, RE.RelType, PCRelVal);
|
||||||
// Insert the value into the instruction.
|
|
||||||
*p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
||||||
case MachO::ARM64_RELOC_PAGE21: {
|
case MachO::ARM64_RELOC_PAGE21: {
|
||||||
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
|
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
|
||||||
// Mask the value into the target address. We know instructions are
|
|
||||||
// 32-bit aligned, so we can do it all at once.
|
|
||||||
uint32_t *p = (uint32_t *)LocalAddress;
|
|
||||||
// Check if the addend is encoded in the instruction.
|
|
||||||
uint32_t EncodedAddend =
|
|
||||||
((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3);
|
|
||||||
if (EncodedAddend != 0) {
|
|
||||||
if (RE.Addend == 0)
|
|
||||||
llvm_unreachable("adrp instruction has embedded addend.");
|
|
||||||
else
|
|
||||||
llvm_unreachable("adrp instruction has embedded addend and"
|
|
||||||
"ARM64_RELOC_ADDEND.");
|
|
||||||
}
|
|
||||||
// Adjust for PC-relative relocation and offset.
|
// Adjust for PC-relative relocation and offset.
|
||||||
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
|
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
|
||||||
uint64_t PCRelVal =
|
int64_t PCRelVal =
|
||||||
((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
|
((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
|
||||||
// Check that the value fits into 21 bits (+ 12 lower bits).
|
encodeAddend(LocalAddress, RE.RelType, PCRelVal);
|
||||||
assert(isInt<33>(PCRelVal) && "Invalid page reloc value!");
|
|
||||||
// Insert the value into the instruction.
|
|
||||||
uint32_t ImmLoValue = (uint32_t)(PCRelVal << 17) & 0x60000000;
|
|
||||||
uint32_t ImmHiValue = (uint32_t)(PCRelVal >> 9) & 0x00FFFFE0;
|
|
||||||
*p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
||||||
case MachO::ARM64_RELOC_PAGEOFF12: {
|
case MachO::ARM64_RELOC_PAGEOFF12: {
|
||||||
assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
|
assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
|
||||||
// Mask the value into the target address. We know instructions are
|
|
||||||
// 32-bit aligned, so we can do it all at once.
|
|
||||||
uint32_t *p = (uint32_t *)LocalAddress;
|
|
||||||
// Check if the addend is encoded in the instruction.
|
|
||||||
uint32_t EncodedAddend = *p & 0x003FFC00;
|
|
||||||
if (EncodedAddend != 0) {
|
|
||||||
if (RE.Addend == 0)
|
|
||||||
llvm_unreachable("adrp instruction has embedded addend.");
|
|
||||||
else
|
|
||||||
llvm_unreachable("adrp instruction has embedded addend and"
|
|
||||||
"ARM64_RELOC_ADDEND.");
|
|
||||||
}
|
|
||||||
// Add the offset from the symbol.
|
// Add the offset from the symbol.
|
||||||
Value += RE.Addend;
|
Value += RE.Addend;
|
||||||
// Mask out the page address and only use the lower 12 bits.
|
// Mask out the page address and only use the lower 12 bits.
|
||||||
Value &= 0xFFF;
|
Value &= 0xFFF;
|
||||||
// Check which instruction we are updating to obtain the implicit shift
|
encodeAddend(LocalAddress, RE.RelType, Value);
|
||||||
// factor from LDR/STR instructions.
|
|
||||||
if (*p & 0x08000000) {
|
|
||||||
uint32_t ImplicitShift = ((*p >> 30) & 0x3);
|
|
||||||
switch (ImplicitShift) {
|
|
||||||
case 0:
|
|
||||||
// Check if this a vector op.
|
|
||||||
if ((*p & 0x04800000) == 0x04800000) {
|
|
||||||
ImplicitShift = 4;
|
|
||||||
assert(((Value & 0xF) == 0) &&
|
|
||||||
"128-bit LDR/STR not 16-byte aligned.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
assert(((Value & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
|
|
||||||
case 2:
|
|
||||||
assert(((Value & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
|
|
||||||
case 3:
|
|
||||||
assert(((Value & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
|
|
||||||
}
|
|
||||||
// Compensate for implicit shift.
|
|
||||||
Value >>= ImplicitShift;
|
|
||||||
}
|
|
||||||
// Insert the value into the instruction.
|
|
||||||
*p = (*p & 0xFFC003FF) | ((uint32_t)(Value << 10) & 0x003FFC00);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MachO::ARM64_RELOC_SUBTRACTOR:
|
case MachO::ARM64_RELOC_SUBTRACTOR:
|
||||||
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
||||||
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
|
||||||
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
|
||||||
llvm_unreachable("Relocation type not implemented yet!");
|
llvm_unreachable("Relocation type not yet implemented!");
|
||||||
case MachO::ARM64_RELOC_ADDEND:
|
case MachO::ARM64_RELOC_ADDEND:
|
||||||
llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
|
llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
|
||||||
"processRelocationRef!");
|
"processRelocationRef!");
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
# RUN: llvm-mc -triple=arm64-apple-ios7.0.0 -code-model=small -relocation-model=pic -filetype=obj -o %t.o %s
|
||||||
|
# RUN: llvm-rtdyld -triple=arm64-apple-ios7.0.0 -verify -check=%s %t.o
|
||||||
|
# RUN: rm %t.o
|
||||||
|
|
||||||
|
# FIXME: Add GOT relocation tests once GOT testing is supported.
|
||||||
|
|
||||||
|
.section __TEXT,__text,regular,pure_instructions
|
||||||
|
.ios_version_min 7, 0
|
||||||
|
.globl foo
|
||||||
|
.align 2
|
||||||
|
foo:
|
||||||
|
movz w0, #0
|
||||||
|
ret
|
||||||
|
|
||||||
|
.globl _test_branch_reloc
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
|
||||||
|
# Test ARM64_RELOC_BRANCH26 relocation. The branch instruction only encodes 26
|
||||||
|
# bits of the 28-bit possible branch range. The lower two bits are always zero
|
||||||
|
# and therefore ignored.
|
||||||
|
# rtdyld-check: decode_operand(br1, 0)[25:0] = (foo-br1)[27:2]
|
||||||
|
_test_branch_reloc:
|
||||||
|
br1:
|
||||||
|
b foo
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# Test ARM64_RELOC_UNSIGNED relocation. The absolute 64-bit address of the
|
||||||
|
# function should be stored at the 8-byte memory location.
|
||||||
|
# rtdyld-check: *{8}ptr = foo
|
||||||
|
.section __DATA,__data
|
||||||
|
.globl ptr
|
||||||
|
.align 3
|
||||||
|
.fill 8192, 1, 0
|
||||||
|
ptr:
|
||||||
|
.quad foo
|
||||||
|
|
||||||
|
|
||||||
|
# Test ARM64_RELOC_PAGE21 and ARM64_RELOC_PAGEOFF12 relocation. adrp encodes
|
||||||
|
# the PC-relative page (4 KiB) difference between the adrp instruction and the
|
||||||
|
# variable ptr. ldr encodes the offset of the variable within the page. The ldr
|
||||||
|
# instruction perfroms an implicit shift on the encoded immediate (imm<<3).
|
||||||
|
# rtdyld-check: decode_operand(adrp1, 1) = (ptr[32:12]-adrp1[32:12])
|
||||||
|
# rtdyld-check: decode_operand(ldr1, 2) = (ptr[11:3])
|
||||||
|
.globl _test_adrp_ldr
|
||||||
|
.align 2
|
||||||
|
_test_adrp_ldr:
|
||||||
|
adrp1:
|
||||||
|
adrp x0, ptr@PAGE
|
||||||
|
ldr1:
|
||||||
|
ldr x0, [x0, ptr@PAGEOFF]
|
||||||
|
ret
|
||||||
|
.fill 8192, 1, 0
|
3
test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg
Normal file
3
test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
if not 'AArch64' in config.root.targets:
|
||||||
|
config.unsupported = True
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user