aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCDwarf.cpp
diff options
context:
space:
mode:
authorSaleem Abdulrasool <abdulras@google.com>2021-05-26 15:41:11 +0000
committerSaleem Abdulrasool <abdulras@google.com>2021-06-17 08:20:02 -0700
commitbbea64250f65480d787e1c5ff45c4de3ec2dcda8 (patch)
tree0a8f3b508a447bd86df8bca83ca0a2022499c8c9 /llvm/lib/MC/MCDwarf.cpp
parentdee2c76b4c46e71903e3d86ab7555a80d51d1288 (diff)
downloadllvm-bbea64250f65480d787e1c5ff45c4de3ec2dcda8.zip
llvm-bbea64250f65480d787e1c5ff45c4de3ec2dcda8.tar.gz
llvm-bbea64250f65480d787e1c5ff45c4de3ec2dcda8.tar.bz2
RISCV: adjust handling of relocation emission for RISCV
This re-architects the RISCV relocation handling to bring the implementation closer in line with the implementation in binutils. We would previously aggressively resolve the relocation. With this restructuring, we always will emit a paired relocation for any symbolic difference of the type of S±T[±C] where S and T are labels and C is a constant. GAS has a special target hook controlled by `RELOC_EXPANSION_POSSIBLE` which indicates that a fixup may be expanded into multiple relocations. This is used by the RISCV backend to always emit a paired relocation - either ADD[WIDTH] + SUB[WIDTH] for text relocations or SET[WIDTH] + SUB[WIDTH] for a debug info relocation. Irrespective of whether linker relaxation support is enabled, symbolic difference is always emitted as a paired relocation. This change also sinks the target specific behaviour down into the target specific area rather than exposing it to the shared relocation handling. In the process, we also sink the "special" handling for debug information down into the RISCV target. Although this improves the path for the other targets, this is not necessarily entirely ideal either. The changes in the debug info emission could be done through another type of hook as this functionality would be required by any other target which wishes to do linker relaxation. However, as there are no other targets in LLVM which currently do this, this is a reasonable thing to do until such time as the code needs to be shared. Improve the handling of the relocation (and add a reduced test case from the Linux kernel) to ensure that we handle complex expressions for symbolic difference. This ensures that we correct relocate symbols with the adddends normalized and associated with the addition portion of the paired relocation. This change also addresses some review comments from Alex Bradbury about the relocations meant for use in the DWARF CFA being named incorrectly (using ADD6 instead of SET6) in the original change which introduced the relocation type. This resolves the issues with the symbolic difference emission sufficiently to enable building the Linux kernel with clang+IAS+lld (without linker relaxation). Resolves PR50153, PR50156! Fixes: ClangBuiltLinux/linux#1023, ClangBuiltLinux/linux#1143 Reviewed By: nickdesaulniers, maskray Differential Revision: https://reviews.llvm.org/D103539
Diffstat (limited to 'llvm/lib/MC/MCDwarf.cpp')
-rw-r--r--llvm/lib/MC/MCDwarf.cpp94
1 files changed, 10 insertions, 84 deletions
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 217584e..27bb7a103 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -734,54 +734,6 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params,
}
}
-std::tuple<uint32_t, uint32_t, bool>
-MCDwarfLineAddr::fixedEncode(MCContext &Context, int64_t LineDelta,
- uint64_t AddrDelta, raw_ostream &OS) {
- uint32_t Offset, Size;
- if (LineDelta != INT64_MAX) {
- OS << char(dwarf::DW_LNS_advance_line);
- encodeSLEB128(LineDelta, OS);
- }
-
- // Use address delta to adjust address or use absolute address to adjust
- // address.
- bool SetDelta;
- // According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a
- // single uhalf (unencoded) operand. So, the maximum value of AddrDelta
- // is 65535. We set a conservative upper bound for it for relaxation.
- if (AddrDelta > 60000) {
- const MCAsmInfo *asmInfo = Context.getAsmInfo();
- unsigned AddrSize = asmInfo->getCodePointerSize();
-
- OS << char(dwarf::DW_LNS_extended_op);
- encodeULEB128(1 + AddrSize, OS);
- OS << char(dwarf::DW_LNE_set_address);
- // Generate fixup for the address.
- Offset = OS.tell();
- Size = AddrSize;
- SetDelta = false;
- OS.write_zeros(AddrSize);
- } else {
- OS << char(dwarf::DW_LNS_fixed_advance_pc);
- // Generate fixup for 2-bytes address delta.
- Offset = OS.tell();
- Size = 2;
- SetDelta = true;
- OS << char(0);
- OS << char(0);
- }
-
- if (LineDelta == INT64_MAX) {
- OS << char(dwarf::DW_LNS_extended_op);
- OS << char(1);
- OS << char(dwarf::DW_LNE_end_sequence);
- } else {
- OS << char(dwarf::DW_LNS_copy);
- }
-
- return std::make_tuple(Offset, Size, SetDelta);
-}
-
// Utility function to write a tuple for .debug_abbrev.
static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
MCOS->emitULEB128IntValue(Name);
@@ -1940,54 +1892,28 @@ void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer,
}
void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context,
- uint64_t AddrDelta, raw_ostream &OS,
- uint32_t *Offset, uint32_t *Size) {
+ uint64_t AddrDelta,
+ raw_ostream &OS) {
// Scale the address delta by the minimum instruction length.
AddrDelta = ScaleAddrDelta(Context, AddrDelta);
-
- bool WithFixups = false;
- if (Offset && Size)
- WithFixups = true;
+ if (AddrDelta == 0)
+ return;
support::endianness E =
Context.getAsmInfo()->isLittleEndian() ? support::little : support::big;
- if (AddrDelta == 0) {
- if (WithFixups) {
- *Offset = 0;
- *Size = 0;
- }
- } else if (isUIntN(6, AddrDelta)) {
+
+ if (isUIntN(6, AddrDelta)) {
uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
- if (WithFixups) {
- *Offset = OS.tell();
- *Size = 6;
- OS << uint8_t(dwarf::DW_CFA_advance_loc);
- } else
- OS << Opcode;
+ OS << Opcode;
} else if (isUInt<8>(AddrDelta)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
- if (WithFixups) {
- *Offset = OS.tell();
- *Size = 8;
- OS.write_zeros(1);
- } else
- OS << uint8_t(AddrDelta);
+ OS << uint8_t(AddrDelta);
} else if (isUInt<16>(AddrDelta)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
- if (WithFixups) {
- *Offset = OS.tell();
- *Size = 16;
- OS.write_zeros(2);
- } else
- support::endian::write<uint16_t>(OS, AddrDelta, E);
+ support::endian::write<uint16_t>(OS, AddrDelta, E);
} else {
assert(isUInt<32>(AddrDelta));
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
- if (WithFixups) {
- *Offset = OS.tell();
- *Size = 32;
- OS.write_zeros(4);
- } else
- support::endian::write<uint32_t>(OS, AddrDelta, E);
+ support::endian::write<uint32_t>(OS, AddrDelta, E);
}
}