[LLD][MachO][NFC] Refactor LOH code (#141153)
In `applyAdrpAddLdr()` we make a transformation that is identical to the one in `applyAdrpAdd()`, so lets reuse that code. Also refactor `forEachHint()` to use more `ArrayRef` and move around some lines for consistancy.
This commit is contained in:
@@ -392,25 +392,26 @@ static void writeImmediateLdr(void *loc, const Ldr &ldr) {
|
||||
// ->
|
||||
// adr xM, _foo
|
||||
// nop
|
||||
static void applyAdrpAdd(uint8_t *buf, const ConcatInputSection *isec,
|
||||
static bool applyAdrpAdd(uint8_t *buf, const ConcatInputSection *isec,
|
||||
uint64_t offset1, uint64_t offset2) {
|
||||
uint32_t ins1 = read32le(buf + offset1);
|
||||
uint32_t ins2 = read32le(buf + offset2);
|
||||
Adrp adrp;
|
||||
Add add;
|
||||
if (!parseAdrp(ins1, adrp) || !parseAdd(ins2, add))
|
||||
return;
|
||||
return false;
|
||||
if (adrp.destRegister != add.srcRegister)
|
||||
return;
|
||||
return false;
|
||||
|
||||
uint64_t addr1 = isec->getVA() + offset1;
|
||||
uint64_t referent = pageBits(addr1) + adrp.addend + add.addend;
|
||||
int64_t delta = referent - addr1;
|
||||
if (!isValidAdrOffset(delta))
|
||||
return;
|
||||
return false;
|
||||
|
||||
writeAdr(buf + offset1, add.destRegister, delta);
|
||||
writeNop(buf + offset2);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transforms two adrp instructions into a single adrp if their referent
|
||||
@@ -495,16 +496,12 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
|
||||
uint64_t offset1, uint64_t offset2,
|
||||
uint64_t offset3) {
|
||||
uint32_t ins1 = read32le(buf + offset1);
|
||||
Adrp adrp;
|
||||
if (!parseAdrp(ins1, adrp))
|
||||
return;
|
||||
uint32_t ins2 = read32le(buf + offset2);
|
||||
Add add;
|
||||
if (!parseAdd(ins2, add))
|
||||
return;
|
||||
uint32_t ins3 = read32le(buf + offset3);
|
||||
Adrp adrp;
|
||||
Add add;
|
||||
Ldr ldr;
|
||||
if (!parseLdr(ins3, ldr))
|
||||
if (!parseAdrp(ins1, adrp) || !parseAdd(ins2, add) || !parseLdr(ins3, ldr))
|
||||
return;
|
||||
if (adrp.destRegister != add.srcRegister)
|
||||
return;
|
||||
@@ -527,18 +524,8 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the target address into a register and load from there indirectly.
|
||||
// adr x1, _foo
|
||||
// nop
|
||||
// ldr x2, [x1, #off]
|
||||
int64_t adrOffset = referent - addr1;
|
||||
if (isValidAdrOffset(adrOffset)) {
|
||||
writeAdr(buf + offset1, ldr.baseRegister, adrOffset);
|
||||
// Note: ld64 moves the offset into the adr instruction for AdrpAddLdr, but
|
||||
// not for AdrpLdrGotLdr. Its effect is the same either way.
|
||||
writeNop(buf + offset2);
|
||||
if (applyAdrpAdd(buf, isec, offset1, offset2))
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the target's page offset into the ldr's immediate offset.
|
||||
// adrp x0, _foo@PAGE
|
||||
@@ -572,67 +559,45 @@ static void applyAdrpLdrGotLdr(uint8_t *buf, const ConcatInputSection *isec,
|
||||
// adrp x1, _foo@GOTPAGE
|
||||
// ldr x2, [x1, _foo@GOTPAGEOFF]
|
||||
// ldr x3, [x2, #off]
|
||||
|
||||
uint32_t ins1 = read32le(buf + offset1);
|
||||
Adrp adrp;
|
||||
if (!parseAdrp(ins1, adrp))
|
||||
return;
|
||||
uint32_t ins3 = read32le(buf + offset3);
|
||||
Ldr ldr3;
|
||||
if (!parseLdr(ins3, ldr3))
|
||||
return;
|
||||
|
||||
if (ldr2.baseRegister != adrp.destRegister)
|
||||
return;
|
||||
if (ldr3.baseRegister != ldr2.destRegister)
|
||||
return;
|
||||
// Loads from the GOT must be pointer sized.
|
||||
if (ldr2.p2Size != 3 || ldr2.isFloat)
|
||||
return;
|
||||
|
||||
uint64_t addr1 = isec->getVA() + offset1;
|
||||
uint64_t addr2 = isec->getVA() + offset2;
|
||||
uint64_t referent = pageBits(addr1) + adrp.addend + ldr2.offset;
|
||||
// Load the GOT entry's address directly.
|
||||
// nop
|
||||
// ldr x2, _foo@GOTPAGE + _foo@GOTPAGEOFF
|
||||
// ldr x3, [x2, #off]
|
||||
Ldr literalLdr = ldr2;
|
||||
literalLdr.offset = referent - addr2;
|
||||
if (isLiteralLdrEligible(literalLdr)) {
|
||||
writeNop(buf + offset1);
|
||||
writeLiteralLdr(buf + offset2, literalLdr);
|
||||
applyAdrpLdr(buf, isec, offset1, offset2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t readValue(const uint8_t *&ptr, const uint8_t *end) {
|
||||
unsigned int n = 0;
|
||||
uint64_t value = decodeULEB128(ptr, &n, end);
|
||||
ptr += n;
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
static void forEachHint(ArrayRef<uint8_t> data, Callback callback) {
|
||||
std::array<uint64_t, 3> args;
|
||||
|
||||
for (const uint8_t *p = data.begin(), *end = data.end(); p < end;) {
|
||||
uint64_t type = readValue(p, end);
|
||||
auto readNext = [&]() -> uint64_t {
|
||||
unsigned int n = 0;
|
||||
uint64_t value = decodeULEB128(data.data(), &n, data.end());
|
||||
data = data.drop_front(n);
|
||||
return value;
|
||||
};
|
||||
|
||||
while (!data.empty()) {
|
||||
uint64_t type = readNext();
|
||||
if (type == 0)
|
||||
break;
|
||||
|
||||
uint64_t argCount = readValue(p, end);
|
||||
// All known LOH types as of 2022-09 have 3 or fewer arguments; skip others.
|
||||
if (argCount > 3) {
|
||||
for (unsigned i = 0; i < argCount; ++i)
|
||||
readValue(p, end);
|
||||
continue;
|
||||
uint64_t argCount = readNext();
|
||||
for (unsigned i = 0; i < argCount; ++i) {
|
||||
uint64_t arg = readNext();
|
||||
if (i < 3)
|
||||
args[i] = arg;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < argCount; ++i)
|
||||
args[i] = readValue(p, end);
|
||||
callback(type, ArrayRef<uint64_t>(args.data(), argCount));
|
||||
// All known LOH types as of 2022-09 have 3 or fewer arguments; skip others.
|
||||
if (argCount > 3)
|
||||
continue;
|
||||
callback(type, ArrayRef(args.data(), argCount));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user