diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-08-03 14:32:30 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-08-03 14:32:30 +0000 |
commit | 8f8ec7ff389bebdde7d14b98698aa753205f9def (patch) | |
tree | 721fb9bae592799d3f5322785fd9372706a3fccb | |
parent | 44230f891eeb122003744afd25bc38f749bf8483 (diff) |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
-rw-r--r-- | gnu/llvm/lld/ELF/Arch/X86_64.cpp | 479 |
1 files changed, 45 insertions, 434 deletions
diff --git a/gnu/llvm/lld/ELF/Arch/X86_64.cpp b/gnu/llvm/lld/ELF/Arch/X86_64.cpp index 514ddc5ec8b..74b72eb9129 100644 --- a/gnu/llvm/lld/ELF/Arch/X86_64.cpp +++ b/gnu/llvm/lld/ELF/Arch/X86_64.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -19,8 +18,9 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; + +namespace lld { +namespace elf { namespace { class X86_64 : public TargetInfo { @@ -32,49 +32,23 @@ public: RelType getDynRel(RelType type) const override; void writeGotPltHeader(uint8_t *buf) const override; void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const override; - void relocate(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; - int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; - void applyJumpInstrMod(uint8_t *loc, JumpModType type, - unsigned size) const override; - - RelExpr adjustGotPcExpr(RelType type, int64_t addend, - const uint8_t *loc) const override; - void relaxGot(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; - void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, - uint64_t val) const override; + void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + + RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, + RelExpr expr) const override; + void relaxGot(uint8_t *loc, RelType type, uint64_t val) const override; + void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; + void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; + void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; + void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, uint8_t stOther) const override; - bool deleteFallThruJmpInsn(InputSection &is, InputFile *file, - InputSection *nextIS) const override; }; } // namespace -// This is vector of NOP instructions of sizes from 1 to 8 bytes. The -// appropriately sized instructions are used to fill the gaps between sections -// which are executed during fall through. -static const std::vector<std::vector<uint8_t>> nopInstructions = { - {0x90}, - {0x66, 0x90}, - {0x0f, 0x1f, 0x00}, - {0x0f, 0x1f, 0x40, 0x00}, - {0x0f, 0x1f, 0x44, 0x00, 0x00}, - {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, - {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, - {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}}; - X86_64::X86_64() { copyRel = R_X86_64_COPY; gotRel = R_X86_64_GLOB_DAT; @@ -87,12 +61,10 @@ X86_64::X86_64() { tlsGotRel = R_X86_64_TPOFF64; tlsModuleIndexRel = R_X86_64_DTPMOD64; tlsOffsetRel = R_X86_64_DTPOFF64; - gotEntrySize = 8; pltHeaderSize = 16; pltEntrySize = 16; ipltEntrySize = 16; trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 - nopInstrs = nopInstructions; // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. @@ -101,216 +73,6 @@ X86_64::X86_64() { int X86_64::getTlsGdRelaxSkip(RelType type) const { return 2; } -// Opcodes for the different X86_64 jmp instructions. -enum JmpInsnOpcode : uint32_t { - J_JMP_32, - J_JNE_32, - J_JE_32, - J_JG_32, - J_JGE_32, - J_JB_32, - J_JBE_32, - J_JL_32, - J_JLE_32, - J_JA_32, - J_JAE_32, - J_UNKNOWN, -}; - -// Given the first (optional) and second byte of the insn's opcode, this -// returns the corresponding enum value. -static JmpInsnOpcode getJmpInsnType(const uint8_t *first, - const uint8_t *second) { - if (*second == 0xe9) - return J_JMP_32; - - if (first == nullptr) - return J_UNKNOWN; - - if (*first == 0x0f) { - switch (*second) { - case 0x84: - return J_JE_32; - case 0x85: - return J_JNE_32; - case 0x8f: - return J_JG_32; - case 0x8d: - return J_JGE_32; - case 0x82: - return J_JB_32; - case 0x86: - return J_JBE_32; - case 0x8c: - return J_JL_32; - case 0x8e: - return J_JLE_32; - case 0x87: - return J_JA_32; - case 0x83: - return J_JAE_32; - } - } - return J_UNKNOWN; -} - -// Return the relocation index for input section IS with a specific Offset. -// Returns the maximum size of the vector if no such relocation is found. -static unsigned getRelocationWithOffset(const InputSection &is, - uint64_t offset) { - unsigned size = is.relocations.size(); - for (unsigned i = size - 1; i + 1 > 0; --i) { - if (is.relocations[i].offset == offset && is.relocations[i].expr != R_NONE) - return i; - } - return size; -} - -// Returns true if R corresponds to a relocation used for a jump instruction. -// TODO: Once special relocations for relaxable jump instructions are available, -// this should be modified to use those relocations. -static bool isRelocationForJmpInsn(Relocation &R) { - return R.type == R_X86_64_PLT32 || R.type == R_X86_64_PC32 || - R.type == R_X86_64_PC8; -} - -// Return true if Relocation R points to the first instruction in the -// next section. -// TODO: Delete this once psABI reserves a new relocation type for fall thru -// jumps. -static bool isFallThruRelocation(InputSection &is, InputFile *file, - InputSection *nextIS, Relocation &r) { - if (!isRelocationForJmpInsn(r)) - return false; - - uint64_t addrLoc = is.getOutputSection()->addr + is.outSecOff + r.offset; - uint64_t targetOffset = InputSectionBase::getRelocTargetVA( - file, r.type, r.addend, addrLoc, *r.sym, r.expr); - - // If this jmp is a fall thru, the target offset is the beginning of the - // next section. - uint64_t nextSectionOffset = - nextIS->getOutputSection()->addr + nextIS->outSecOff; - return (addrLoc + 4 + targetOffset) == nextSectionOffset; -} - -// Return the jmp instruction opcode that is the inverse of the given -// opcode. For example, JE inverted is JNE. -static JmpInsnOpcode invertJmpOpcode(const JmpInsnOpcode opcode) { - switch (opcode) { - case J_JE_32: - return J_JNE_32; - case J_JNE_32: - return J_JE_32; - case J_JG_32: - return J_JLE_32; - case J_JGE_32: - return J_JL_32; - case J_JB_32: - return J_JAE_32; - case J_JBE_32: - return J_JA_32; - case J_JL_32: - return J_JGE_32; - case J_JLE_32: - return J_JG_32; - case J_JA_32: - return J_JBE_32; - case J_JAE_32: - return J_JB_32; - default: - return J_UNKNOWN; - } -} - -// Deletes direct jump instruction in input sections that jumps to the -// following section as it is not required. If there are two consecutive jump -// instructions, it checks if they can be flipped and one can be deleted. -// For example: -// .section .text -// a.BB.foo: -// ... -// 10: jne aa.BB.foo -// 16: jmp bar -// aa.BB.foo: -// ... -// -// can be converted to: -// a.BB.foo: -// ... -// 10: je bar #jne flipped to je and the jmp is deleted. -// aa.BB.foo: -// ... -bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file, - InputSection *nextIS) const { - const unsigned sizeOfDirectJmpInsn = 5; - - if (nextIS == nullptr) - return false; - - if (is.getSize() < sizeOfDirectJmpInsn) - return false; - - // If this jmp insn can be removed, it is the last insn and the - // relocation is 4 bytes before the end. - unsigned rIndex = getRelocationWithOffset(is, is.getSize() - 4); - if (rIndex == is.relocations.size()) - return false; - - Relocation &r = is.relocations[rIndex]; - - // Check if the relocation corresponds to a direct jmp. - const uint8_t *secContents = is.data().data(); - // If it is not a direct jmp instruction, there is nothing to do here. - if (*(secContents + r.offset - 1) != 0xe9) - return false; - - if (isFallThruRelocation(is, file, nextIS, r)) { - // This is a fall thru and can be deleted. - r.expr = R_NONE; - r.offset = 0; - is.drop_back(sizeOfDirectJmpInsn); - is.nopFiller = true; - return true; - } - - // Now, check if flip and delete is possible. - const unsigned sizeOfJmpCCInsn = 6; - // To flip, there must be atleast one JmpCC and one direct jmp. - if (is.getSize() < sizeOfDirectJmpInsn + sizeOfJmpCCInsn) - return 0; - - unsigned rbIndex = - getRelocationWithOffset(is, (is.getSize() - sizeOfDirectJmpInsn - 4)); - if (rbIndex == is.relocations.size()) - return 0; - - Relocation &rB = is.relocations[rbIndex]; - - const uint8_t *jmpInsnB = secContents + rB.offset - 1; - JmpInsnOpcode jmpOpcodeB = getJmpInsnType(jmpInsnB - 1, jmpInsnB); - if (jmpOpcodeB == J_UNKNOWN) - return false; - - if (!isFallThruRelocation(is, file, nextIS, rB)) - return false; - - // jmpCC jumps to the fall thru block, the branch can be flipped and the - // jmp can be deleted. - JmpInsnOpcode jInvert = invertJmpOpcode(jmpOpcodeB); - if (jInvert == J_UNKNOWN) - return false; - is.jumpInstrMods.push_back({jInvert, (rB.offset - 1), 4}); - // Move R's values to rB except the offset. - rB = {r.expr, r.type, rB.offset, r.addend, r.sym}; - // Cancel R - r.expr = R_NONE; - r.offset = 0; - is.drop_back(sizeOfDirectJmpInsn); - is.nopFiller = true; - return true; -} - RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { if (type == R_X86_64_GOTTPOFF) @@ -327,7 +89,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, case R_X86_64_DTPOFF64: return R_DTPREL; case R_X86_64_TPOFF32: - return R_TPREL; + return R_TLS; case R_X86_64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_X86_64_TLSLD: @@ -381,12 +143,6 @@ void X86_64::writeGotPlt(uint8_t *buf, const Symbol &s) const { write64le(buf, s.getPltVA() + 6); } -void X86_64::writeIgotPlt(uint8_t *buf, const Symbol &s) const { - // An x86 entry is the address of the ifunc resolver function (for -z rel). - if (config->writeAddends) - write64le(buf, s.getVA()); -} - void X86_64::writePltHeader(uint8_t *buf) const { const uint8_t pltData[] = { 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip) @@ -421,9 +177,8 @@ RelType X86_64::getDynRel(RelType type) const { return R_X86_64_NONE; } -void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, - uint64_t val) const { - if (rel.type == R_X86_64_TLSGD) { +void X86_64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { + if (type == R_X86_64_TLSGD) { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi @@ -446,7 +201,7 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, // lea x@tlsgd(%rip), %rax // call *(%rax) // to the following two instructions. - assert(rel.type == R_X86_64_GOTPC32_TLSDESC); + assert(type == R_X86_64_GOTPC32_TLSDESC); if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " "in callq *x@tlsdesc(%rip), %rax"); @@ -462,9 +217,8 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, } } -void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, - uint64_t val) const { - if (rel.type == R_X86_64_TLSGD) { +void X86_64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { + if (type == R_X86_64_TLSGD) { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi @@ -487,7 +241,7 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, // lea x@tlsgd(%rip), %rax // call *(%rax) // to the following two instructions. - assert(rel.type == R_X86_64_GOTPC32_TLSDESC); + assert(type == R_X86_64_GOTPC32_TLSDESC); if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " "in callq *x@tlsdesc(%rip), %rax"); @@ -504,8 +258,7 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. -void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &, - uint64_t val) const { +void X86_64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { uint8_t *inst = loc - 3; uint8_t reg = loc[-1] >> 3; uint8_t *regSlot = loc - 1; @@ -546,13 +299,12 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &, write32le(loc, val + 4); } -void X86_64::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, - uint64_t val) const { - if (rel.type == R_X86_64_DTPOFF64) { +void X86_64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { + if (type == R_X86_64_DTPOFF64) { write64le(loc, val); return; } - if (rel.type == R_X86_64_DTPOFF32) { + if (type == R_X86_64_DTPOFF32) { write32le(loc, val); return; } @@ -595,163 +347,26 @@ void X86_64::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, "expected R_X86_64_PLT32 or R_X86_64_GOTPCRELX after R_X86_64_TLSLD"); } -// A JumpInstrMod at a specific offset indicates that the jump instruction -// opcode at that offset must be modified. This is specifically used to relax -// jump instructions with basic block sections. This function looks at the -// JumpMod and effects the change. -void X86_64::applyJumpInstrMod(uint8_t *loc, JumpModType type, - unsigned size) const { - switch (type) { - case J_JMP_32: - if (size == 4) - *loc = 0xe9; - else - *loc = 0xeb; - break; - case J_JE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x84; - } else - *loc = 0x74; - break; - case J_JNE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x85; - } else - *loc = 0x75; - break; - case J_JG_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x8f; - } else - *loc = 0x7f; - break; - case J_JGE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x8d; - } else - *loc = 0x7d; - break; - case J_JB_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x82; - } else - *loc = 0x72; - break; - case J_JBE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x86; - } else - *loc = 0x76; - break; - case J_JL_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x8c; - } else - *loc = 0x7c; - break; - case J_JLE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x8e; - } else - *loc = 0x7e; - break; - case J_JA_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x87; - } else - *loc = 0x77; - break; - case J_JAE_32: - if (size == 4) { - loc[-1] = 0x0f; - *loc = 0x83; - } else - *loc = 0x73; - break; - case J_UNKNOWN: - llvm_unreachable("Unknown Jump Relocation"); - } -} - -int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const { +void X86_64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { switch (type) { case R_X86_64_8: - case R_X86_64_PC8: - return SignExtend64<8>(*buf); - case R_X86_64_16: - case R_X86_64_PC16: - return SignExtend64<16>(read16le(buf)); - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_TPOFF32: - case R_X86_64_GOT32: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC32_TLSDESC: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PC32: - case R_X86_64_GOTTPOFF: - case R_X86_64_PLT32: - case R_X86_64_TLSGD: - case R_X86_64_TLSLD: - case R_X86_64_DTPOFF32: - case R_X86_64_SIZE32: - return SignExtend64<32>(read32le(buf)); - case R_X86_64_64: - case R_X86_64_TPOFF64: - case R_X86_64_DTPOFF64: - case R_X86_64_DTPMOD64: - case R_X86_64_PC64: - case R_X86_64_SIZE64: - case R_X86_64_GLOB_DAT: - case R_X86_64_GOT64: - case R_X86_64_GOTOFF64: - case R_X86_64_GOTPC64: - case R_X86_64_IRELATIVE: - case R_X86_64_RELATIVE: - return read64le(buf); - case R_X86_64_JUMP_SLOT: - case R_X86_64_NONE: - // These relocations are defined as not having an implicit addend. - return 0; - default: - internalLinkerError(getErrorLocation(buf), - "cannot read addend for relocation " + toString(type)); - return 0; - } -} - -void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { - switch (rel.type) { - case R_X86_64_8: - checkIntUInt(loc, val, 8, rel); + checkIntUInt(loc, val, 8, type); *loc = val; break; case R_X86_64_PC8: - checkInt(loc, val, 8, rel); + checkInt(loc, val, 8, type); *loc = val; break; case R_X86_64_16: - checkIntUInt(loc, val, 16, rel); + checkIntUInt(loc, val, 16, type); write16le(loc, val); break; case R_X86_64_PC16: - checkInt(loc, val, 16, rel); + checkInt(loc, val, 16, type); write16le(loc, val); break; case R_X86_64_32: - checkUInt(loc, val, 32, rel); + checkUInt(loc, val, 32, type); write32le(loc, val); break; case R_X86_64_32S: @@ -769,7 +384,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: - checkInt(loc, val, 32, rel); + checkInt(loc, val, 32, type); write32le(loc, val); break; case R_X86_64_64: @@ -786,17 +401,12 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { } } -RelExpr X86_64::adjustGotPcExpr(RelType type, int64_t addend, - const uint8_t *loc) const { - // Only R_X86_64_[REX_]GOTPCRELX can be relaxed. GNU as may emit GOTPCRELX - // with addend != -4. Such an instruction does not load the full GOT entry, so - // we cannot relax the relocation. E.g. movl x@GOTPCREL+4(%rip), %rax - // (addend=0) loads the high 32 bits of the GOT entry. - if ((type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX) || - addend != -4) - return R_GOT_PC; - const uint8_t op = loc[-2]; - const uint8_t modRm = loc[-1]; +RelExpr X86_64::adjustRelaxExpr(RelType type, const uint8_t *data, + RelExpr relExpr) const { + if (type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX) + return relExpr; + const uint8_t op = data[-2]; + const uint8_t modRm = data[-1]; // FIXME: When PIC is disabled and foo is defined locally in the // lower 32 bit address space, memory operand in mov can be converted into @@ -809,13 +419,12 @@ RelExpr X86_64::adjustGotPcExpr(RelType type, int64_t addend, if (op == 0xff && (modRm == 0x15 || modRm == 0x25)) return R_RELAX_GOT_PC; - // We don't support test/binop instructions without a REX prefix. - if (type == R_X86_64_GOTPCRELX) - return R_GOT_PC; - // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. // If PIC then no relaxation is available. - return config->isPic ? R_GOT_PC : R_RELAX_GOT_PC_NOPIC; + // We also don't relax test/binop instructions without REX byte, + // they are 32bit operations and not common to have. + assert(type == R_X86_64_REX_GOTPCRELX); + return config->isPic ? relExpr : R_RELAX_GOT_PC_NOPIC; } // A subset of relaxations can only be applied for no-PIC. This method @@ -886,8 +495,7 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, write32le(loc, val); } -void X86_64::relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const { - checkInt(loc, val, 32, rel); +void X86_64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { const uint8_t op = loc[-2]; const uint8_t modRm = loc[-1]; @@ -1150,4 +758,7 @@ static TargetInfo *getTargetInfo() { return &t; } -TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } +TargetInfo *getX86_64TargetInfo() { return getTargetInfo(); } + +} // namespace elf +} // namespace lld |