diff options
Diffstat (limited to 'lld')
100 files changed, 1450 insertions, 601 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 548d87b..409491d 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -946,7 +946,7 @@ void ECCodeMapChunk::writeTo(uint8_t *buf) const { auto table = reinterpret_cast<chpe_range_entry *>(buf); for (uint32_t i = 0; i < map.size(); i++) { const ECCodeMapEntry &entry = map[i]; - uint32_t start = entry.first->getRVA(); + uint32_t start = entry.first->getRVA() & ~0xfff; table[i].StartOffset = start | entry.type; table[i].Length = entry.last->getRVA() + entry.last->getSize() - start; } diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 10a3934..42c7f93 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -862,6 +862,9 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) { << "', did you mean '" << nearest << "'"; } + if (args.hasArg(OPT_link)) + Warn(ctx) << "ignoring /link, did you pass it multiple times?"; + if (args.hasArg(OPT_lib)) Warn(ctx) << "ignoring /lib since it's not the first argument"; diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index d77478f..6c4c7f8 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -71,6 +71,7 @@ def noimplib : F<"noimplib">, def lib : F<"lib">, HelpText<"Act like lib.exe; must be first argument if present">; def libpath : P<"libpath", "Additional library search path">; +def link : F<"link">, HelpText<"Ignored for compatibility">; def linkrepro : Joined<["/", "-", "/?", "-?"], "linkrepro:">, MetaVarName<"directory">, HelpText<"Write repro.tar containing inputs and command to reproduce link">; diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 2a97df4..4613539 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -114,6 +114,7 @@ AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) { copyRel = R_AARCH64_COPY; relativeRel = R_AARCH64_RELATIVE; iRelativeRel = R_AARCH64_IRELATIVE; + iRelSymbolicRel = R_AARCH64_FUNCINIT64; gotRel = R_AARCH64_GLOB_DAT; pltRel = R_AARCH64_JUMP_SLOT; symbolicRel = R_AARCH64_ABS64; @@ -137,6 +138,7 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_ABS16: case R_AARCH64_ABS32: case R_AARCH64_ABS64: + case R_AARCH64_FUNCINIT64: case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: @@ -267,7 +269,8 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const { } RelType AArch64::getDynRel(RelType type) const { - if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64) + if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64 || + type == R_AARCH64_FUNCINIT64) return type; return R_AARCH64_NONE; } @@ -762,7 +765,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, relocateNoSym(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val); break; default: - llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } } diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 5ed89e4..7ec75b0 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -8,6 +8,7 @@ #include "InputFiles.h" #include "OutputSections.h" +#include "RISCVInternalRelocations.h" #include "RelocScan.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -345,8 +346,15 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, case R_RISCV_SUB_ULEB128: return RE_RISCV_LEB128; default: - Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v - << ") against symbol " << &s; + if (type.v & INTERNAL_RISCV_VENDOR_MASK) { + Err(ctx) << getErrorLoc(ctx, loc) + << "unsupported vendor-specific relocation " << type + << " against symbol " << &s; + return R_NONE; + } + Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" + << (type.v & ~INTERNAL_RISCV_VENDOR_MASK) << ") against symbol " + << &s; return R_NONE; } } @@ -859,7 +867,7 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) { std::fill_n(aux.relocTypes.get(), relocs.size(), R_RISCV_NONE); aux.writes.clear(); - for (auto [i, r] : llvm::enumerate(relocs)) { + for (auto [i, r] : llvm::enumerate(riscv_vendor_relocs(relocs))) { const uint64_t loc = secAddr + r.offset - delta; uint32_t &cur = aux.relocDeltas[i], remove = 0; switch (r.type) { @@ -1503,12 +1511,19 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { rvVendor = sym.getName(); continue; } else if (!rvVendor.empty()) { - Err(ctx) << getErrorLoc(ctx, loc) - << "unknown vendor-specific relocation (" << type.v - << ") in namespace '" << rvVendor << "' against symbol '" << &sym - << "'"; + uint32_t VendorFlag = getRISCVVendorRelMarker(rvVendor); + if (!VendorFlag) { + Err(ctx) << getErrorLoc(ctx, loc) + << "unknown vendor-specific relocation (" << type.v + << ") in namespace '" << rvVendor << "' against symbol '" + << &sym << "'"; + rvVendor = ""; + continue; + } + rvVendor = ""; - continue; + assert((type.v < 256) && "Out of range relocation detected!"); + type.v |= VendorFlag; } rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type)); @@ -1533,3 +1548,21 @@ template <class ELFT> void RISCV::scanSection1(InputSectionBase &sec) { void RISCV::scanSection(InputSectionBase &sec) { invokeELFT(scanSection1, sec); } + +namespace lld::elf { +uint32_t getRISCVVendorRelMarker(StringRef rvVendor) { + return StringSwitch<uint32_t>(rvVendor) + .Case("QUALCOMM", INTERNAL_RISCV_VENDOR_QUALCOMM) + .Case("ANDES", INTERNAL_RISCV_VENDOR_ANDES) + .Default(0); +} + +std::optional<StringRef> getRISCVVendorString(RelType ty) { + if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_QUALCOMM) + return "QUALCOMM"; + if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_ANDES) + return "ANDES"; + return std::nullopt; +} + +} // namespace lld::elf diff --git a/lld/ELF/Arch/RISCVInternalRelocations.h b/lld/ELF/Arch/RISCVInternalRelocations.h new file mode 100644 index 0000000..35e2f53 --- /dev/null +++ b/lld/ELF/Arch/RISCVInternalRelocations.h @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H +#define LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H + +#include "Relocations.h" +#include "Symbols.h" + +namespace lld::elf { + +// Bit 8 of RelType is used to indicate linker-internal relocations that are +// not vendor-specific. +// These are internal relocation numbers for GP/X0 relaxation. They aren't part +// of the psABI spec. +constexpr uint32_t INTERNAL_R_RISCV_GPREL_I = 256; +constexpr uint32_t INTERNAL_R_RISCV_GPREL_S = 257; +constexpr uint32_t INTERNAL_R_RISCV_X0REL_I = 258; +constexpr uint32_t INTERNAL_R_RISCV_X0REL_S = 259; + +// Bits 9 -> 31 of RelType are used to indicate vendor-specific relocations. +constexpr uint32_t INTERNAL_RISCV_VENDOR_MASK = 0xFFFFFFFF << 9; +constexpr uint32_t INTERNAL_RISCV_VENDOR_QUALCOMM = 1 << 9; +constexpr uint32_t INTERNAL_RISCV_VENDOR_ANDES = 2 << 9; + +constexpr uint32_t INTERNAL_RISCV_QC_ABS20_U = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_ABS20_U; +constexpr uint32_t INTERNAL_RISCV_QC_E_BRANCH = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_BRANCH; +constexpr uint32_t INTERNAL_RISCV_QC_E_32 = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_32; +constexpr uint32_t INTERNAL_RISCV_QC_E_CALL_PLT = + INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_CALL_PLT; + +constexpr uint32_t INTERNAL_RISCV_NDS_BRANCH_10 = + INTERNAL_RISCV_VENDOR_ANDES | llvm::ELF::R_RISCV_NDS_BRANCH_10; + +uint32_t getRISCVVendorRelMarker(llvm::StringRef rvVendor); +std::optional<llvm::StringRef> getRISCVVendorString(RelType ty); + +class vendor_reloc_iterator { +public: + using iterator_category = std::forward_iterator_tag; + using value_type = Relocation; + using difference_type = std::ptrdiff_t; + using pointer = Relocation *; + using reference = Relocation; // returned by value + + vendor_reloc_iterator(MutableArrayRef<Relocation>::iterator i, + MutableArrayRef<Relocation>::iterator e) + : it(i), end(e) {} + + // Dereference + Relocation operator*() const { + Relocation r = *it; + r.type.v |= rvVendorFlag; + return r; + } + + struct vendor_reloc_proxy { + Relocation r; + const Relocation *operator->() const { return &r; } + }; + + vendor_reloc_proxy operator->() const { + return vendor_reloc_proxy{this->operator*()}; + } + + vendor_reloc_iterator &operator++() { + ++it; + if (it != end && it->type == llvm::ELF::R_RISCV_VENDOR) { + rvVendorFlag = getRISCVVendorRelMarker(it->sym->getName()); + ++it; + } else { + rvVendorFlag = 0; + } + return *this; + } + + vendor_reloc_iterator operator++(int) { + vendor_reloc_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(const vendor_reloc_iterator &other) const { + return it == other.it; + } + bool operator!=(const vendor_reloc_iterator &other) const { + return it != other.it; + } + + Relocation *getUnderlyingRelocation() const { return &*it; } + +private: + MutableArrayRef<Relocation>::iterator it; + MutableArrayRef<Relocation>::iterator end; + uint32_t rvVendorFlag = 0; +}; + +inline auto riscv_vendor_relocs(MutableArrayRef<Relocation> arr) { + return llvm::make_range(vendor_reloc_iterator(arr.begin(), arr.end()), + vendor_reloc_iterator(arr.end(), arr.end())); +} + +} // namespace lld::elf + +#endif diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index a5921fe..240a6d0 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1676,8 +1676,9 @@ template <class ELFT> void SharedFile::parse() { const uint16_t ver = versyms[i], idx = ver & ~VERSYM_HIDDEN; if (sym.isUndefined()) { - // For unversioned undefined symbols, VER_NDX_GLOBAL makes more sense but - // as of binutils 2.34, GNU ld produces VER_NDX_LOCAL. + // Index 0 (VER_NDX_LOCAL) is used for unversioned undefined symbols. + // GNU ld versions between 2.35 and 2.45 also generate VER_NDX_GLOBAL + // for this case (https://sourceware.org/PR33577). if (ver != VER_NDX_LOCAL && ver != VER_NDX_GLOBAL) { if (idx >= verneeds.size()) { ErrAlways(ctx) << "corrupt input file: version need index " << idx diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 75184de..c2111e5 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -154,7 +154,7 @@ def bp_startup_sort: JJ<"bp-startup-sort=">, MetaVarName<"[none,function]">, // Auxiliary options related to balanced partition defm bp_compression_sort_startup_functions: BB<"bp-compression-sort-startup-functions", - "When --irpgo-profile is pecified, prioritize function similarity for compression in addition to startup time", "">; + "When --irpgo-profile is specified, prioritize function similarity for compression in addition to startup time", "">; def verbose_bp_section_orderer: FF<"verbose-bp-section-orderer">, HelpText<"Print information on balanced partitioning">; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index d21376f..59aa430 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -849,8 +849,8 @@ bool RelocScan::isStaticLinkTimeConstant(RelExpr e, RelType type, // only the low bits are used. if (e == R_GOT || e == R_PLT) return ctx.target->usesOnlyLowPageBits(type) || !ctx.arg.isPic; - // R_AARCH64_AUTH_ABS64 requires a dynamic relocation. - if (e == RE_AARCH64_AUTH) + // R_AARCH64_AUTH_ABS64 and iRelSymbolicRel require a dynamic relocation. + if (e == RE_AARCH64_AUTH || type == ctx.target->iRelSymbolicRel) return false; // The behavior of an undefined weak reference is implementation defined. @@ -1023,6 +1023,23 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset, } return; } + if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) { + if (sym.isPreemptible) { + auto diag = Err(ctx); + diag << "relocation " << type + << " cannot be used against preemptible symbol '" << &sym << "'"; + printLocation(diag, *sec, sym, offset); + } else if (isIfunc) { + auto diag = Err(ctx); + diag << "relocation " << type + << " cannot be used against ifunc symbol '" << &sym << "'"; + printLocation(diag, *sec, sym, offset); + } else { + part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false, + sym, addend, R_ABS}); + return; + } + } part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type); // MIPS ABI turns using of GOT and dynamic relocations inside out. @@ -1278,7 +1295,7 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type, // label, so TLSDESC=>IE will be categorized as R_RELAX_TLS_GD_TO_LE. We fix // the categorization in RISCV::relocateAllosec-> if (sym.isPreemptible) { - sym.setFlags(NEEDS_TLSGD_TO_IE); + sym.setFlags(NEEDS_TLSIE); sec->addReloc({ctx.target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset, addend, &sym}); } else { @@ -1618,18 +1635,13 @@ void elf::postScanRelocations(Ctx &ctx) { else got->addConstant({R_ABS, ctx.target->tlsOffsetRel, offsetOff, 0, &sym}); } - if (flags & NEEDS_TLSGD_TO_IE) { - got->addEntry(sym); - ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsGotRel, *got, - sym.getGotOffset(ctx), sym); - } if (flags & NEEDS_GOT_DTPREL) { got->addEntry(sym); got->addConstant( {R_ABS, ctx.target->tlsOffsetRel, sym.getGotOffset(ctx), 0, &sym}); } - if ((flags & NEEDS_TLSIE) && !(flags & NEEDS_TLSGD_TO_IE)) + if (flags & NEEDS_TLSIE) addTpOffsetGotEntry(ctx, sym); }; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c117e3b..034c873 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -48,7 +48,7 @@ enum { NEEDS_COPY = 1 << 3, NEEDS_TLSDESC = 1 << 4, NEEDS_TLSGD = 1 << 5, - NEEDS_TLSGD_TO_IE = 1 << 6, + // 1 << 6 unused NEEDS_GOT_DTPREL = 1 << 7, NEEDS_TLSIE = 1 << 8, NEEDS_GOT_AUTH = 1 << 9, @@ -313,6 +313,8 @@ public: // represents the Verdef index within the input DSO, which will be converted // to a Verneed index in the output. Otherwise, this represents the Verdef // index (VER_NDX_LOCAL, VER_NDX_GLOBAL, or a named version). + // VER_NDX_LOCAL indicates a defined symbol that has been localized by a + // version script's local: directive or --exclude-libs. uint16_t versionId; LLVM_PREFERRED_TYPE(bool) uint8_t versionScriptAssigned : 1; @@ -350,7 +352,7 @@ public: bool needsDynReloc() const { return flags.load(std::memory_order_relaxed) & (NEEDS_COPY | NEEDS_GOT | NEEDS_PLT | NEEDS_TLSDESC | NEEDS_TLSGD | - NEEDS_TLSGD_TO_IE | NEEDS_GOT_DTPREL | NEEDS_TLSIE); + NEEDS_GOT_DTPREL | NEEDS_TLSIE); } void allocateAux(Ctx &ctx) { assert(auxIdx == 0); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index a4150eb..1e9d44f 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -54,8 +54,6 @@ using llvm::support::endian::read32le; using llvm::support::endian::write32le; using llvm::support::endian::write64le; -constexpr size_t MergeNoTailSection::numShards; - static uint64_t readUint(Ctx &ctx, uint8_t *buf) { return ctx.arg.is64 ? read64(ctx, buf) : read32(ctx, buf); } @@ -542,43 +540,6 @@ void EhFrameSection::finalizeContents() { this->size = off; } -// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table -// to get an FDE from an address to which FDE is applied. This function -// returns a list of such pairs. -SmallVector<EhFrameSection::FdeData, 0> EhFrameSection::getFdeData() const { - uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff; - SmallVector<FdeData, 0> ret; - - uint64_t va = getPartition(ctx).ehFrameHdr->getVA(); - for (CieRecord *rec : cieRecords) { - uint8_t enc = getFdeEncoding(rec->cie); - for (EhSectionPiece *fde : rec->fdes) { - uint64_t pc = getFdePc(buf, fde->outputOff, enc); - uint64_t fdeVA = getParent()->addr + fde->outputOff; - if (!isInt<32>(pc - va)) { - Err(ctx) << fde->sec << ": PC offset is too large: 0x" - << Twine::utohexstr(pc - va); - continue; - } - ret.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); - } - } - - // Sort the FDE list by their PC and uniqueify. Usually there is only - // one FDE for a PC (i.e. function), but if ICF merges two functions - // into one, there can be more than one FDEs pointing to the address. - auto less = [](const FdeData &a, const FdeData &b) { - return a.pcRel < b.pcRel; - }; - llvm::stable_sort(ret, less); - auto eq = [](const FdeData &a, const FdeData &b) { - return a.pcRel == b.pcRel; - }; - ret.erase(llvm::unique(ret, eq), ret.end()); - - return ret; -} - static uint64_t readFdeAddr(Ctx &ctx, uint8_t *buf, int size) { switch (size) { case DW_EH_PE_udata2: @@ -632,14 +593,79 @@ void EhFrameSection::writeTo(uint8_t *buf) { } } - // Apply relocations. .eh_frame section contents are not contiguous - // in the output buffer, but relocateAlloc() still works because - // getOffset() takes care of discontiguous section pieces. + // Apply relocations to .eh_frame entries. This includes CIE personality + // pointers, FDE initial_location fields, and LSDA pointers. for (EhInputSection *s : sections) ctx.target->relocateEh(*s, buf); - if (getPartition(ctx).ehFrameHdr && getPartition(ctx).ehFrameHdr->getParent()) - getPartition(ctx).ehFrameHdr->write(); + EhFrameHeader *hdr = getPartition(ctx).ehFrameHdr.get(); + if (!hdr || !hdr->getParent()) + return; + + // Write the .eh_frame_hdr section, which contains a binary search table of + // pointers to FDEs. This must be written after .eh_frame relocation since + // the content depends on relocated initial_location fields in FDEs. + using FdeData = EhFrameSection::FdeData; + SmallVector<FdeData, 0> fdes; + uint64_t va = hdr->getVA(); + for (CieRecord *rec : cieRecords) { + uint8_t enc = getFdeEncoding(rec->cie); + for (EhSectionPiece *fde : rec->fdes) { + uint64_t pc = getFdePc(buf, fde->outputOff, enc); + uint64_t fdeVA = getParent()->addr + fde->outputOff; + if (!isInt<32>(pc - va)) { + Err(ctx) << fde->sec << ": PC offset is too large: 0x" + << Twine::utohexstr(pc - va); + continue; + } + fdes.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); + } + } + + // Sort the FDE list by their PC and uniqueify. Usually there is only + // one FDE for a PC (i.e. function), but if ICF merges two functions + // into one, there can be more than one FDEs pointing to the address. + llvm::stable_sort(fdes, [](const FdeData &a, const FdeData &b) { + return a.pcRel < b.pcRel; + }); + fdes.erase( + llvm::unique(fdes, [](auto &a, auto &b) { return a.pcRel == b.pcRel; }), + fdes.end()); + + // Write header. + uint8_t *hdrBuf = ctx.bufferStart + hdr->getParent()->offset + hdr->outSecOff; + hdrBuf[0] = 1; // version + hdrBuf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; // eh_frame_ptr_enc + hdrBuf[2] = DW_EH_PE_udata4; // fde_count_enc + hdrBuf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; // table_enc + write32(ctx, hdrBuf + 4, + getParent()->addr - hdr->getVA() - 4); // eh_frame_ptr + write32(ctx, hdrBuf + 8, fdes.size()); // fde_count + hdrBuf += 12; + + // Write binary search table. Each entry describes the starting PC and the FDE + // address. + for (FdeData &fde : fdes) { + write32(ctx, hdrBuf, fde.pcRel); + write32(ctx, hdrBuf + 4, fde.fdeVARel); + hdrBuf += 8; + } +} + +EhFrameHeader::EhFrameHeader(Ctx &ctx) + : SyntheticSection(ctx, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 4) {} + +void EhFrameHeader::writeTo(uint8_t *buf) { + // The section content is written during EhFrameSection::writeTo. +} + +size_t EhFrameHeader::getSize() const { + // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. + return 12 + getPartition(ctx).ehFrame->numFdes * 8; +} + +bool EhFrameHeader::isNeeded() const { + return isLive() && getPartition(ctx).ehFrame->isNeeded(); } GotSection::GotSection(Ctx &ctx) @@ -2749,9 +2775,9 @@ RelroPaddingSection::RelroPaddingSection(Ctx &ctx) : SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE, 1) {} -PaddingSection::PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent) - : SyntheticSection(ctx, ".padding", SHT_PROGBITS, SHF_ALLOC, 1), - size(size) { +PaddingSection::PaddingSection(Ctx &ctx, uint64_t amount, OutputSection *parent) + : SyntheticSection(ctx, ".padding", SHT_PROGBITS, SHF_ALLOC, 1) { + size = amount; this->parent = parent; } @@ -3660,51 +3686,6 @@ void GdbIndexSection::writeTo(uint8_t *buf) { bool GdbIndexSection::isNeeded() const { return !chunks.empty(); } -EhFrameHeader::EhFrameHeader(Ctx &ctx) - : SyntheticSection(ctx, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 4) {} - -void EhFrameHeader::writeTo(uint8_t *buf) { - // Unlike most sections, the EhFrameHeader section is written while writing - // another section, namely EhFrameSection, which calls the write() function - // below from its writeTo() function. This is necessary because the contents - // of EhFrameHeader depend on the relocated contents of EhFrameSection and we - // don't know which order the sections will be written in. -} - -// .eh_frame_hdr contains a binary search table of pointers to FDEs. -// Each entry of the search table consists of two values, -// the starting PC from where FDEs covers, and the FDE's address. -// It is sorted by PC. -void EhFrameHeader::write() { - uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff; - using FdeData = EhFrameSection::FdeData; - SmallVector<FdeData, 0> fdes = getPartition(ctx).ehFrame->getFdeData(); - - buf[0] = 1; - buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; - buf[2] = DW_EH_PE_udata4; - buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - write32(ctx, buf + 4, - getPartition(ctx).ehFrame->getParent()->addr - this->getVA() - 4); - write32(ctx, buf + 8, fdes.size()); - buf += 12; - - for (FdeData &fde : fdes) { - write32(ctx, buf, fde.pcRel); - write32(ctx, buf + 4, fde.fdeVARel); - buf += 8; - } -} - -size_t EhFrameHeader::getSize() const { - // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - return 12 + getPartition(ctx).ehFrame->numFdes * 8; -} - -bool EhFrameHeader::isNeeded() const { - return isLive() && getPartition(ctx).ehFrame->isNeeded(); -} - VersionDefinitionSection::VersionDefinitionSection(Ctx &ctx) : SyntheticSection(ctx, ".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC, sizeof(uint32_t)) {} @@ -3786,9 +3767,10 @@ void VersionTableSection::writeTo(uint8_t *buf) { buf += 2; for (const SymbolTableEntry &s : getPartition(ctx).dynSymTab->getSymbols()) { // For an unextracted lazy symbol (undefined weak), it must have been - // converted to Undefined and have VER_NDX_GLOBAL version here. + // converted to Undefined. assert(!s.sym->isLazy()); - write16(ctx, buf, s.sym->versionId); + // Undefined symbols should use index 0 when unversioned. + write16(ctx, buf, s.sym->isUndefined() ? 0 : s.sym->versionId); buf += 2; } } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 38e6811..e01a5ad 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -68,7 +68,6 @@ public: uint32_t fdeVARel; }; - SmallVector<FdeData, 0> getFdeData() const; ArrayRef<CieRecord *> getCieRecords() const { return cieRecords; } template <class ELFT> void iterateFDEWithLSDA(llvm::function_ref<void(InputSection &)> fn); @@ -78,8 +77,6 @@ private: // allocating one for each EhInputSection. llvm::DenseMap<size_t, CieRecord *> offsetToCie; - uint64_t size = 0; - template <llvm::endianness E> void addRecords(EhInputSection *s); template <class ELFT> void iterateFDEWithLSDAAux(EhInputSection &sec, @@ -97,6 +94,17 @@ private: llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> cieMap; }; +// .eh_frame_hdr contains a binary search table for .eh_frame FDEs. The section +// is covered by a PT_GNU_EH_FRAME segment, which allows the runtime unwinder to +// locate it via functions like `dl_iterate_phdr`. +class EhFrameHeader final : public SyntheticSection { +public: + EhFrameHeader(Ctx &); + void writeTo(uint8_t *buf) override; + size_t getSize() const override; + bool isNeeded() const override; +}; + class GotSection final : public SyntheticSection { public: GotSection(Ctx &); @@ -127,7 +135,6 @@ public: protected: size_t numEntries = 0; uint32_t tlsIndexOff = -1; - uint64_t size = 0; struct AuthEntryInfo { size_t offset; bool isSymbolFunc; @@ -182,7 +189,6 @@ public: static bool classof(const SectionBase *s) { return isa<SyntheticSection>(s) && cast<SyntheticSection>(s)->bss; } - uint64_t size; }; class MipsGotSection final : public SyntheticSection { @@ -312,8 +318,6 @@ private: // Number of "Header" entries. static const unsigned headerEntriesNum = 2; - uint64_t size = 0; - // Symbol and addend. using GotEntry = std::pair<Symbol *, int64_t>; @@ -407,8 +411,6 @@ public: private: const bool dynamic; - uint64_t size = 0; - llvm::DenseMap<llvm::CachedHashStringRef, unsigned> stringMap; SmallVector<StringRef, 0> strings; }; @@ -475,7 +477,6 @@ public: private: std::vector<std::pair<int32_t, uint64_t>> computeContents(); - uint64_t size = 0; }; class RelocationBaseSection : public SyntheticSection { @@ -780,10 +781,8 @@ public: }; class PaddingSection final : public SyntheticSection { - uint64_t size; - public: - PaddingSection(Ctx &ctx, uint64_t size, OutputSection *parent); + PaddingSection(Ctx &ctx, uint64_t amount, OutputSection *parent); size_t getSize() const override { return size; } void writeTo(uint8_t *buf) override; }; @@ -978,24 +977,6 @@ private: size_t size; }; -// --eh-frame-hdr option tells linker to construct a header for all the -// .eh_frame sections. This header is placed to a section named .eh_frame_hdr -// and also to a PT_GNU_EH_FRAME segment. -// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by -// calling dl_iterate_phdr. -// This section contains a lookup table for quick binary search of FDEs. -// Detailed info about internals can be found in Ian Lance Taylor's blog: -// http://www.airs.com/blog/archives/460 (".eh_frame") -// http://www.airs.com/blog/archives/462 (".eh_frame_hdr") -class EhFrameHeader final : public SyntheticSection { -public: - EhFrameHeader(Ctx &); - void write(); - void writeTo(uint8_t *buf) override; - size_t getSize() const override; - bool isNeeded() const override; -}; - // For more information about .gnu.version and .gnu.version_r see: // https://www.akkadia.org/drepper/symbol-versioning diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 89e4dbe..3fc3e3f 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -24,6 +24,7 @@ //===----------------------------------------------------------------------===// #include "Target.h" +#include "Arch/RISCVInternalRelocations.h" #include "InputFiles.h" #include "OutputSections.h" #include "RelocScan.h" @@ -40,6 +41,14 @@ using namespace lld::elf; std::string elf::toStr(Ctx &ctx, RelType type) { StringRef s = getELFRelocationTypeName(ctx.arg.emachine, type); + if (ctx.arg.emachine == EM_RISCV && s == "Unknown") { + auto VendorString = getRISCVVendorString(type); + if (VendorString) + s = getRISCVVendorRelocationTypeName(type & ~INTERNAL_RISCV_VENDOR_MASK, + *VendorString); + if (s == "Unknown") + return ("Unknown vendor-specific (" + Twine(type) + ")").str(); + } if (s == "Unknown") return ("Unknown (" + Twine(type) + ")").str(); return std::string(s); diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 90d8ddf..8da0b5c 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -145,6 +145,7 @@ public: RelType relativeRel = 0; RelType iRelativeRel = 0; RelType symbolicRel = 0; + RelType iRelSymbolicRel = 0; RelType tlsDescRel = 0; RelType tlsGotRel = 0; RelType tlsModuleIndexRel = 0; diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp index 111c4d9..f351399 100644 --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -54,7 +54,8 @@ static constexpr std::array<RelocAttrs, 10> relocAttrsArray{{ {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE1) | B(BYTE4) | B(BYTE8)}, {"SIGNED", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)}, - {"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE1) | B(BYTE4)}, + {"BRANCH", + B(PCREL) | B(EXTERN) | B(LOCAL) | B(BRANCH) | B(BYTE1) | B(BYTE4)}, {"GOT_LOAD", B(PCREL) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)}, {"GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)}, {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)}, diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp index 8067d23..e559676 100644 --- a/lld/MachO/ConcatOutputSection.cpp +++ b/lld/MachO/ConcatOutputSection.cpp @@ -306,7 +306,7 @@ void TextOutputSection::finalize() { // contains several branch instructions in succession, then the distance // from the current position to the position where the thunks are inserted // grows. So leave room for a bunch of thunks. - unsigned slop = 256 * thunkSize; + unsigned slop = config->slopScale * thunkSize; while (finalIdx < endIdx) { uint64_t expectedNewSize = alignToPowerOf2(addr + size, inputs[finalIdx]->align) + @@ -384,7 +384,9 @@ void TextOutputSection::finalize() { // above. If you hit this: For the current algorithm, just bumping up // slop above and trying again is probably simplest. (See also PR51578 // comment 5). - fatal(Twine(__FUNCTION__) + ": FIXME: thunk range overrun"); + fatal(Twine(__FUNCTION__) + + ": FIXME: thunk range overrun. Consider increasing the " + "slop-scale with `--slop-scale=<unsigned_int>`."); } thunkInfo.isec = makeSyntheticInputSection(isec->getSegName(), isec->getName()); diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index a2ca577..759a8cb 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -224,6 +224,7 @@ struct Configuration { bool disableVerify; bool separateCstringLiteralSections; bool tailMergeStrings; + unsigned slopScale = 256; bool callGraphProfileSort = false; llvm::StringRef printSymbolOrder; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index 32b2099..f4f3aba 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -41,6 +41,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" @@ -53,6 +54,10 @@ #include "llvm/TextAPI/Architecture.h" #include "llvm/TextAPI/PackedVersion.h" +#if !_WIN32 +#include <sys/mman.h> +#endif + using namespace llvm; using namespace llvm::MachO; using namespace llvm::object; @@ -292,12 +297,13 @@ struct DeferredFile { using DeferredFiles = std::vector<DeferredFile>; #if LLVM_ENABLE_THREADS -class SerialBackgroundQueue { +class SerialBackgroundWorkQueue { std::deque<std::function<void()>> queue; std::thread *running; std::mutex mutex; public: + std::atomic_bool stopAllWork = false; void queueWork(std::function<void()> work) { mutex.lock(); if (running && queue.empty()) { @@ -312,7 +318,7 @@ public: queue.emplace_back(std::move(work)); if (!running) running = new std::thread([&]() { - while (true) { + while (!stopAllWork) { mutex.lock(); if (queue.empty()) { mutex.unlock(); @@ -331,6 +337,8 @@ public: } }; +static SerialBackgroundWorkQueue pageInQueue; + // Most input files have been mapped but not yet paged in. // This code forces the page-ins on multiple threads so // the process is not stalled waiting on disk buffer i/o. @@ -339,8 +347,8 @@ void multiThreadedPageInBackground(DeferredFiles &deferred) { static const size_t largeArchive = 10 * 1024 * 1024; #ifndef NDEBUG using namespace std::chrono; - std::atomic_int numDeferedFilesTouched = 0; static std::atomic_uint64_t totalBytes = 0; + std::atomic_int numDeferedFilesAdvised = 0; auto t0 = high_resolution_clock::now(); #endif @@ -348,24 +356,34 @@ void multiThreadedPageInBackground(DeferredFiles &deferred) { const StringRef &buff = deferredFile.buffer.getBuffer(); if (buff.size() > largeArchive) return; + #ifndef NDEBUG totalBytes += buff.size(); - numDeferedFilesTouched += 1; + numDeferedFilesAdvised += 1; #endif - +#if _WIN32 // Reference all file's mmap'd pages to load them into memory. - for (const char *page = buff.data(), *end = page + buff.size(); page < end; - page += pageSize) { + for (const char *page = buff.data(), *end = page + buff.size(); + page < end && !pageInQueue.stopAllWork; page += pageSize) { [[maybe_unused]] volatile char t = *page; (void)t; } +#else +#define DEBUG_TYPE "lld-madvise" + auto aligned = + llvm::alignDown(reinterpret_cast<uintptr_t>(buff.data()), pageSize); + if (madvise((void *)aligned, buff.size(), MADV_WILLNEED) < 0) + LLVM_DEBUG(llvm::dbgs() << "madvise error: " << strerror(errno) << "\n"); +#undef DEBUG_TYPE +#endif }; + { // Create scope for waiting for the taskGroup std::atomic_size_t index = 0; llvm::parallel::TaskGroup taskGroup; for (int w = 0; w < config->readWorkers; w++) taskGroup.spawn([&index, &preloadDeferredFile, &deferred]() { - while (true) { + while (!pageInQueue.stopAllWork) { size_t localIndex = index.fetch_add(1); if (localIndex >= deferred.size()) break; @@ -373,17 +391,17 @@ void multiThreadedPageInBackground(DeferredFiles &deferred) { } }); } + #ifndef NDEBUG auto dt = high_resolution_clock::now() - t0; if (Process::GetEnv("LLD_MULTI_THREAD_PAGE")) llvm::dbgs() << "multiThreadedPageIn " << totalBytes << "/" - << numDeferedFilesTouched << "/" << deferred.size() << "/" + << numDeferedFilesAdvised << "/" << deferred.size() << "/" << duration_cast<milliseconds>(dt).count() / 1000. << "\n"; #endif } static void multiThreadedPageIn(const DeferredFiles &deferred) { - static SerialBackgroundQueue pageInQueue; pageInQueue.queueWork([=]() { DeferredFiles files = deferred; multiThreadedPageInBackground(files); @@ -489,7 +507,7 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer, continue; } - if (archiveContents) + if (config->readWorkers && archiveContents) archiveContents->push_back({path, isLazy, *mb}); if (!hasObjCSection(*mb)) continue; @@ -1447,6 +1465,8 @@ static void createFiles(const InputArgList &args) { multiThreadedPageIn(archiveContents); for (auto *archive : archives) archive->addLazySymbols(); + + pageInQueue.stopAllWork = true; } #endif } @@ -1845,8 +1865,8 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS, "'"); config->readWorkers = workers; #else - error(arg->getSpelling() + - ": option unavailable because lld was not built with thread support"); + warn(arg->getSpelling() + + ": option unavailable because lld was not built with thread support"); #endif } if (auto *arg = args.getLastArg(OPT_threads_eq)) { @@ -1995,6 +2015,14 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS, OPT_no_separate_cstring_literal_sections, false); config->tailMergeStrings = args.hasFlag(OPT_tail_merge_strings, OPT_no_tail_merge_strings, false); + if (auto *arg = args.getLastArg(OPT_slop_scale_eq)) { + StringRef v(arg->getValue()); + unsigned slop = 0; + if (!llvm::to_integer(v, slop)) + error(arg->getSpelling() + + ": expected a non-negative integer, but got '" + v + "'"); + config->slopScale = slop; + } auto IncompatWithCGSort = [&](StringRef firstArgStr) { // Throw an error only if --call-graph-profile-sort is explicitly specified diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp index 7b31378c3..e0fc897 100644 --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -173,14 +173,37 @@ bool ICF::equalsConstant(const ConcatInputSection *ia, // a valid offset in the literal section. return isecA->getOffset(valueA) == isecB->getOffset(valueB) && ra.addend == rb.addend; - else { - assert(valueA == 0 && valueB == 0); - // For section relocs, we compare the content at the section offset. - return isecA->getOffset(ra.addend) == isecB->getOffset(rb.addend); - } + assert(valueA == 0 && valueB == 0); + // For section relocs, we compare the content at the section offset. + return isecA->getOffset(ra.addend) == isecB->getOffset(rb.addend); }; - return std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(), - f); + if (!llvm::equal(ia->relocs, ib->relocs, f)) + return false; + + // Check unwind info structural compatibility: if there are symbols with + // associated unwind info, check that both sections have compatible symbol + // layouts. For simplicity, we only attempt folding when all symbols are at + // offset zero within the section (which is typically the case with + // .subsections_via_symbols.) + auto hasUnwind = [](Defined *d) { return d->unwindEntry() != nullptr; }; + const auto *itA = llvm::find_if(ia->symbols, hasUnwind); + const auto *itB = llvm::find_if(ib->symbols, hasUnwind); + if (itA == ia->symbols.end()) + return itB == ib->symbols.end(); + if (itB == ib->symbols.end()) + return false; + const Defined *da = *itA; + const Defined *db = *itB; + if (da->value != 0 || db->value != 0) + return false; + auto isZero = [](Defined *d) { return d->value == 0; }; + // Since symbols are stored in order of value, and since we have already + // checked that da/db have value zero, we just need to do the isZero check on + // the subsequent symbols. + return std::find_if_not(std::next(itA), ia->symbols.end(), isZero) == + ia->symbols.end() && + std::find_if_not(std::next(itB), ib->symbols.end(), isZero) == + ib->symbols.end(); } // Compare the "moving" parts of two ConcatInputSections -- i.e. everything not @@ -217,31 +240,19 @@ bool ICF::equalsVariable(const ConcatInputSection *ia, } return isecA->icfEqClass[icfPass % 2] == isecB->icfEqClass[icfPass % 2]; }; - if (!std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(), f)) + if (!llvm::equal(ia->relocs, ib->relocs, f)) return false; - // If there are symbols with associated unwind info, check that the unwind - // info matches. For simplicity, we only handle the case where there are only - // symbols at offset zero within the section (which is typically the case with - // .subsections_via_symbols.) + // Compare unwind info equivalence classes. auto hasUnwind = [](Defined *d) { return d->unwindEntry() != nullptr; }; const auto *itA = llvm::find_if(ia->symbols, hasUnwind); - const auto *itB = llvm::find_if(ib->symbols, hasUnwind); if (itA == ia->symbols.end()) - return itB == ib->symbols.end(); - if (itB == ib->symbols.end()) - return false; + return true; const Defined *da = *itA; - const Defined *db = *itB; - if (da->unwindEntry()->icfEqClass[icfPass % 2] != - db->unwindEntry()->icfEqClass[icfPass % 2] || - da->value != 0 || db->value != 0) - return false; - auto isZero = [](Defined *d) { return d->value == 0; }; - return std::find_if_not(std::next(itA), ia->symbols.end(), isZero) == - ia->symbols.end() && - std::find_if_not(std::next(itB), ib->symbols.end(), isZero) == - ib->symbols.end(); + // equalsConstant() guarantees that both sections have unwind info. + const Defined *db = *llvm::find_if(ib->symbols, hasUnwind); + return da->unwindEntry()->icfEqClass[icfPass % 2] == + db->unwindEntry()->icfEqClass[icfPass % 2]; } // Find the first InputSection after BEGIN whose equivalence class differs diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index 20e4a1d..81caef5 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -217,7 +217,8 @@ std::optional<MemoryBufferRef> macho::readFile(StringRef path) { if (entry != cachedReads.end()) return entry->second; - ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path); + ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = + MemoryBuffer::getFile(path, false, /*RequiresNullTerminator=*/false); if (std::error_code ec = mbOrErr.getError()) { error("cannot open " + path + ": " + ec.message()); return std::nullopt; @@ -594,8 +595,8 @@ void ObjFile::parseRelocations(ArrayRef<SectionHeader> sectionHeaders, // FIXME This logic was written around x86_64 behavior -- ARM64 doesn't // have pcrel section relocations. We may want to factor this out into // the arch-specific .cpp file. - assert(target->hasAttr(r.type, RelocAttrBits::BYTE4)); - referentOffset = sec.addr + relInfo.r_address + 4 + totalAddend - + referentOffset = sec.addr + relInfo.r_address + + (1ull << relInfo.r_length) + totalAddend - referentSecHead.addr; } else { // The addend for a non-pcrel relocation is its absolute address. @@ -808,6 +809,17 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders, continue; if ((sym.n_type & N_TYPE) == N_SECT) { + if (sym.n_sect == 0) { + fatal("section symbol " + StringRef(strtab + sym.n_strx) + " in " + + toString(this) + " has an invalid section index [0]"); + } + if (sym.n_sect > sections.size()) { + fatal("section symbol " + StringRef(strtab + sym.n_strx) + " in " + + toString(this) + " has an invalid section index [" + + Twine(static_cast<unsigned>(sym.n_sect)) + + "] greater than the total number of sections [" + + Twine(sections.size()) + "]"); + } Subsections &subsections = sections[sym.n_sect - 1]->subsections; // parseSections() may have chosen not to parse this section. if (subsections.empty()) diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index be1a1cc..f5f7549 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -1095,6 +1095,14 @@ defm tail_merge_strings : BB<"tail-merge-strings", "Enable string tail merging", "Disable string tail merging to improve link-time performance">, Group<grp_rare>; +def slop_scale_eq + : Joined<["--"], "slop_scale=">, + MetaVarName<"<unsigned_int>">, + HelpText<"Specify the slop scale. Default value is 256. If your binary " + "has too many consecutive branch instructions resulting in " + "thunk-range overrun, then you need to increase this value to a " + "higher value, such as 512 or 1024, etc">, + Group<grp_rare>; def grp_deprecated : OptionGroup<"deprecated">, HelpText<"DEPRECATED">; diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp index cf657aa..b652d1e 100644 --- a/lld/MachO/SectionPriorities.cpp +++ b/lld/MachO/SectionPriorities.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/xxhash.h" #include <numeric> @@ -246,33 +247,45 @@ DenseMap<const InputSection *, int> CallGraphSort::run() { return orderMap; } -std::optional<int> -macho::PriorityBuilder::getSymbolOrCStringPriority(const StringRef key, - InputFile *f) { +void macho::PriorityBuilder::SymbolPriorityEntry::setPriority( + int priority, StringRef objectFile) { + if (!objectFile.empty()) + objectFiles.try_emplace(objectFile, priority); + else + anyObjectFile = std::min(anyObjectFile, priority); +} - auto it = priorities.find(key); - if (it == priorities.end()) - return std::nullopt; - const SymbolPriorityEntry &entry = it->second; +int macho::PriorityBuilder::SymbolPriorityEntry::getPriority( + const InputFile *f) const { if (!f) - return entry.anyObjectFile; + return anyObjectFile; // We don't use toString(InputFile *) here because it returns the full path // for object files, and we only want the basename. - StringRef filename; - if (f->archiveName.empty()) - filename = path::filename(f->getName()); - else - filename = saver().save(path::filename(f->archiveName) + "(" + - path::filename(f->getName()) + ")"); - return std::min(entry.objectFiles.lookup(filename), entry.anyObjectFile); + StringRef basename = path::filename(f->getName()); + StringRef filename = + f->archiveName.empty() + ? basename + : saver().save(path::filename(f->archiveName) + "(" + basename + ")"); + return std::min(objectFiles.lookup(filename), anyObjectFile); } std::optional<int> -macho::PriorityBuilder::getSymbolPriority(const Defined *sym) { +macho::PriorityBuilder::getCStringPriority(uint32_t hash, + const InputFile *f) const { + auto it = cStringPriorities.find(hash); + if (it == cStringPriorities.end()) + return std::nullopt; + return it->second.getPriority(f); +} + +std::optional<int> +macho::PriorityBuilder::getSymbolPriority(const Defined *sym) const { if (sym->isAbsolute()) return std::nullopt; - return getSymbolOrCStringPriority(utils::getRootSymbol(sym->getName()), - sym->isec()->getFile()); + auto it = priorities.find(utils::getRootSymbol(sym->getName())); + if (it == priorities.end()) + return std::nullopt; + return it->second.getPriority(sym->isec()->getFile()); } void macho::PriorityBuilder::extractCallGraphProfile() { @@ -307,7 +320,7 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) { int prio = std::numeric_limits<int>::min(); MemoryBufferRef mbref = *buffer; for (StringRef line : args::getLines(mbref)) { - StringRef objectFile, symbolOrCStrHash; + StringRef objectFile; line = line.take_until([](char c) { return c == '#'; }); // ignore comments line = line.ltrim(); @@ -338,22 +351,16 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) { } // The rest of the line is either <symbol name> or - // CStringEntryPrefix<cstring hash> + // cStringEntryPrefix<cstring hash> line = line.trim(); - if (line.starts_with(CStringEntryPrefix)) { - StringRef possibleHash = line.drop_front(CStringEntryPrefix.size()); + if (line.consume_front(cStringEntryPrefix)) { uint32_t hash = 0; - if (to_integer(possibleHash, hash)) - symbolOrCStrHash = possibleHash; - } else - symbolOrCStrHash = utils::getRootSymbol(line); - - if (!symbolOrCStrHash.empty()) { - SymbolPriorityEntry &entry = priorities[symbolOrCStrHash]; - if (!objectFile.empty()) - entry.objectFiles.insert(std::make_pair(objectFile, prio)); - else - entry.anyObjectFile = std::min(entry.anyObjectFile, prio); + if (to_integer(line, hash)) + cStringPriorities[hash].setPriority(prio, objectFile); + } else { + StringRef symbol = utils::getRootSymbol(line); + if (!symbol.empty()) + priorities[symbol].setPriority(prio, objectFile); } ++prio; @@ -405,40 +412,39 @@ macho::PriorityBuilder::buildInputSectionPriorities() { return sectionPriorities; } -std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities( - ArrayRef<CStringInputSection *> inputs) { - // Split the input strings into hold and cold sets. - // Order hot set based on -order_file_cstring for performance improvement; - // TODO: Order cold set of cstrings for compression via BP. - std::vector<std::pair<int, StringPiecePair>> - hotStringPrioritiesAndStringPieces; - std::vector<StringPiecePair> coldStringPieces; - std::vector<StringPiecePair> orderedStringPieces; - +void macho::PriorityBuilder::forEachStringPiece( + ArrayRef<CStringInputSection *> inputs, + std::function<void(CStringInputSection &, StringPiece &, size_t)> f, + bool forceInputOrder, bool computeHash) const { + std::vector<std::tuple<int, CStringInputSection *, size_t>> orderedPieces; + std::vector<std::pair<CStringInputSection *, size_t>> unorderedPieces; for (CStringInputSection *isec : inputs) { for (const auto &[stringPieceIdx, piece] : llvm::enumerate(isec->pieces)) { if (!piece.live) continue; - - std::optional<int> priority = getSymbolOrCStringPriority( - std::to_string(piece.hash), isec->getFile()); - if (!priority) - coldStringPieces.emplace_back(isec, stringPieceIdx); + // Process pieces in input order if we have no cstrings in our orderfile + if (forceInputOrder || cStringPriorities.empty()) { + f(*isec, piece, stringPieceIdx); + continue; + } + uint32_t hash = + computeHash + ? (xxh3_64bits(isec->getStringRef(stringPieceIdx)) & 0x7fffffff) + : piece.hash; + if (auto priority = getCStringPriority(hash, isec->getFile())) + orderedPieces.emplace_back(*priority, isec, stringPieceIdx); else - hotStringPrioritiesAndStringPieces.emplace_back( - *priority, std::make_pair(isec, stringPieceIdx)); + unorderedPieces.emplace_back(isec, stringPieceIdx); } } - - // Order hot set for perf - llvm::stable_sort(hotStringPrioritiesAndStringPieces); - for (auto &[priority, stringPiecePair] : hotStringPrioritiesAndStringPieces) - orderedStringPieces.push_back(stringPiecePair); - - // TODO: Order cold set for compression - - orderedStringPieces.insert(orderedStringPieces.end(), - coldStringPieces.begin(), coldStringPieces.end()); - - return orderedStringPieces; + if (orderedPieces.empty() && unorderedPieces.empty()) + return; + llvm::stable_sort(orderedPieces, [](const auto &left, const auto &right) { + return std::get<0>(left) < std::get<0>(right); + }); + for (auto &[priority, isec, pieceIdx] : orderedPieces) + f(*isec, isec->pieces[pieceIdx], pieceIdx); + // TODO: Add option to order the remaining cstrings for compression + for (auto &[isec, pieceIdx] : unorderedPieces) + f(*isec, isec->pieces[pieceIdx], pieceIdx); } diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h index cc4e30f..24d2dbc 100644 --- a/lld/MachO/SectionPriorities.h +++ b/lld/MachO/SectionPriorities.h @@ -16,7 +16,6 @@ namespace lld::macho { using SectionPair = std::pair<const InputSection *, const InputSection *>; -using StringPiecePair = std::pair<CStringInputSection *, size_t>; class PriorityBuilder { public: @@ -29,7 +28,7 @@ public: // // An order file has one entry per line, in the following format: // - // <cpu>:<object file>:[<symbol name> | CStringEntryPrefix <cstring hash>] + // <cpu>:<object file>:[<symbol name> | cStringEntryPrefix <cstring hash>] // // <cpu> and <object file> are optional. // If not specified, then that entry tries to match either, @@ -42,7 +41,7 @@ public: // lowest-ordered entry (the one nearest to the front of the list.) // // or 2) any cstring literal with the given hash, if the entry has the - // CStringEntryPrefix prefix defined below in the file. <cstring hash> is the + // cStringEntryPrefix prefix defined below in the file. <cstring hash> is the // hash of cstring literal content. // // Cstring literals are not symbolized, we can't identify them by name @@ -54,6 +53,16 @@ public: // The file can also have line comments that start with '#'. void parseOrderFile(StringRef path); + /// Call \p f for each string piece in \p inputs. If there are any cstring + /// literals in the orderfile (and \p forceInputOrder is false) then string + /// pieces are ordered by the orderfile. \p computeHash must be set when + /// \p deduplicateLiterals is false because then the string piece hash is not + /// set. + void forEachStringPiece( + ArrayRef<CStringInputSection *> inputs, + std::function<void(CStringInputSection &, StringPiece &, size_t)> f, + bool forceInputOrder = false, bool computeHash = false) const; + // Returns layout priorities for some or all input sections. Sections are laid // out in decreasing order; that is, a higher priority section will be closer // to the beginning of its output section. @@ -66,8 +75,6 @@ public: // Each section gets assigned the priority of the highest-priority symbol it // contains. llvm::DenseMap<const InputSection *, int> buildInputSectionPriorities(); - std::vector<StringPiecePair> - buildCStringPriorities(ArrayRef<CStringInputSection *>); private: // The symbol with the smallest priority should be ordered first in the output @@ -78,13 +85,16 @@ private: int anyObjectFile = 0; // The priority given to a matching symbol from a particular object file. llvm::DenseMap<llvm::StringRef, int> objectFiles; + void setPriority(int priority, StringRef objectFile); + int getPriority(const InputFile *f) const; }; - const llvm::StringRef CStringEntryPrefix = "CSTR;"; + const llvm::StringRef cStringEntryPrefix = "CSTR;"; - std::optional<int> getSymbolPriority(const Defined *sym); - std::optional<int> getSymbolOrCStringPriority(const StringRef key, - InputFile *f); + std::optional<int> getSymbolPriority(const Defined *sym) const; + std::optional<int> getCStringPriority(uint32_t hash, + const InputFile *f) const; llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities; + llvm::DenseMap<uint32_t, SymbolPriorityEntry> cStringPriorities; llvm::MapVector<SectionPair, uint64_t> callGraphProfile; }; diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp index baddddc..a7db5a3a 100644 --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -61,8 +61,8 @@ struct DuplicateSymbolDiag { SmallVector<DuplicateSymbolDiag> dupSymDiags; } // namespace -// Move symbols at \p fromOff in \p fromIsec into \p toIsec, unless that symbol -// is \p skip. +// Move local symbols at \p fromOff in \p fromIsec into \p toIsec, unless that +// symbol is \p skip, in which case we just remove it. static void transplantSymbolsAtOffset(InputSection *fromIsec, InputSection *toIsec, Defined *skip, uint64_t fromOff, uint64_t toOff) { @@ -78,22 +78,23 @@ static void transplantSymbolsAtOffset(InputSection *fromIsec, auto insertIt = llvm::upper_bound(toIsec->symbols, toOff, symSucceedsOff); llvm::erase_if(fromIsec->symbols, [&](Symbol *s) { auto *d = cast<Defined>(s); - if (d->value != fromOff) + if (d == skip) + return true; + if (d->value != fromOff || d->isExternal()) return false; - if (d != skip) { - // This repeated insertion will be quadratic unless insertIt is the end - // iterator. However, that is typically the case for files that have - // .subsections_via_symbols set. - insertIt = toIsec->symbols.insert(insertIt, d); - d->originalIsec = toIsec; - d->value = toOff; - // We don't want to have more than one unwindEntry at a given address, so - // drop the redundant ones. We We can safely drop the unwindEntries of - // the symbols in fromIsec since we will be adding another unwindEntry as - // we finish parsing toIsec's file. (We can assume that toIsec has its - // own unwindEntry because of the ODR.) - d->originalUnwindEntry = nullptr; - } + + // This repeated insertion will be quadratic unless insertIt is the end + // iterator. However, that is typically the case for files that have + // .subsections_via_symbols set. + insertIt = toIsec->symbols.insert(insertIt, d); + d->originalIsec = toIsec; + d->value = toOff; + // We don't want to have more than one unwindEntry at a given address, so + // drop the redundant ones. We can safely drop the unwindEntries of the + // symbols in fromIsec since we will be adding another unwindEntry as we + // finish parsing toIsec's file. (We can assume that toIsec has its own + // unwindEntry because of the ODR.) + d->originalUnwindEntry = nullptr; return true; }); } diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 187cccb..fecc51f 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1721,26 +1721,24 @@ void CStringSection::writeTo(uint8_t *buf) const { // and don't need this alignment. They will be emitted at some arbitrary address // `A`, but ld64 will treat them as being 16-byte aligned with an offset of // `16 % A`. -static Align getStringPieceAlignment(const CStringInputSection *isec, +static Align getStringPieceAlignment(const CStringInputSection &isec, const StringPiece &piece) { - return llvm::Align(1ULL << llvm::countr_zero(isec->align | piece.inSecOff)); + return llvm::Align(1ULL << llvm::countr_zero(isec.align | piece.inSecOff)); } void CStringSection::finalizeContents() { size = 0; - // TODO: Call buildCStringPriorities() to support cstring ordering when - // deduplication is off, although this may negatively impact build - // performance. - for (CStringInputSection *isec : inputs) { - for (const auto &[i, piece] : llvm::enumerate(isec->pieces)) { - if (!piece.live) - continue; - piece.outSecOff = alignTo(size, getStringPieceAlignment(isec, piece)); - StringRef string = isec->getStringRef(i); - size = piece.outSecOff + string.size() + 1; // account for null terminator - } + priorityBuilder.forEachStringPiece( + inputs, + [&](CStringInputSection &isec, StringPiece &piece, size_t pieceIdx) { + piece.outSecOff = alignTo(size, getStringPieceAlignment(isec, piece)); + StringRef string = isec.getStringRef(pieceIdx); + size = + piece.outSecOff + string.size() + 1; // account for null terminator + }, + /*forceInputOrder=*/false, /*computeHash=*/true); + for (CStringInputSection *isec : inputs) isec->isFinal = true; - } } void DeduplicatedCStringSection::finalizeContents() { @@ -1748,20 +1746,19 @@ void DeduplicatedCStringSection::finalizeContents() { DenseMap<CachedHashStringRef, Align> strToAlignment; // Used for tail merging only std::vector<CachedHashStringRef> deduplicatedStrs; - for (const CStringInputSection *isec : inputs) { - for (const auto &[i, piece] : llvm::enumerate(isec->pieces)) { - if (!piece.live) - continue; - auto s = isec->getCachedHashStringRef(i); - assert(isec->align != 0); - auto align = getStringPieceAlignment(isec, piece); - auto [it, wasInserted] = strToAlignment.try_emplace(s, align); - if (config->tailMergeStrings && wasInserted) - deduplicatedStrs.push_back(s); - if (!wasInserted && it->second < align) - it->second = align; - } - } + priorityBuilder.forEachStringPiece( + inputs, + [&](CStringInputSection &isec, StringPiece &piece, size_t pieceIdx) { + auto s = isec.getCachedHashStringRef(pieceIdx); + assert(isec.align != 0); + auto align = getStringPieceAlignment(isec, piece); + auto [it, wasInserted] = strToAlignment.try_emplace(s, align); + if (config->tailMergeStrings && wasInserted) + deduplicatedStrs.push_back(s); + if (!wasInserted && it->second < align) + it->second = align; + }, + /*forceInputOrder=*/true); // Like lexigraphical sort, except we read strings in reverse and take the // longest string first @@ -1801,9 +1798,10 @@ void DeduplicatedCStringSection::finalizeContents() { // Sort the strings for performance and compression size win, and then // assign an offset for each string and save it to the corresponding // StringPieces for easy access. - for (auto &[isec, i] : priorityBuilder.buildCStringPriorities(inputs)) { - auto &piece = isec->pieces[i]; - auto s = isec->getCachedHashStringRef(i); + priorityBuilder.forEachStringPiece(inputs, [&](CStringInputSection &isec, + StringPiece &piece, + size_t pieceIdx) { + auto s = isec.getCachedHashStringRef(pieceIdx); // Any string can be tail merged with itself with an offset of zero uint64_t tailMergeOffset = 0; auto mergeIt = @@ -1829,7 +1827,7 @@ void DeduplicatedCStringSection::finalizeContents() { stringOffsetMap[tailMergedString] = piece.outSecOff; assert(isAligned(strToAlignment.at(tailMergedString), piece.outSecOff)); } - } + }); for (CStringInputSection *isec : inputs) isec->isFinal = true; } diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp index 6e9f6c2..bf01b12 100644 --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -153,8 +153,6 @@ private: // The entries here will be in the same order as their originating symbols // in symbolsVec. std::vector<CompactUnwindEntry> cuEntries; - // Indices into the cuEntries vector. - std::vector<size_t> cuIndices; std::vector<Symbol *> personalities; SmallDenseMap<std::pair<InputSection *, uint64_t /* addend */>, Symbol *> personalityTable; @@ -400,8 +398,7 @@ void UnwindInfoSectionImpl::relocateCompactUnwind( // There should only be a handful of unique personality pointers, so we can // encode them as 2-bit indices into a small array. void UnwindInfoSectionImpl::encodePersonalities() { - for (size_t idx : cuIndices) { - CompactUnwindEntry &cu = cuEntries[idx]; + for (CompactUnwindEntry &cu : cuEntries) { if (cu.personality == nullptr) continue; // Linear search is fast enough for a small array. @@ -467,27 +464,24 @@ void UnwindInfoSectionImpl::finalize() { symbolsVec = symbols.takeVector(); relocateCompactUnwind(cuEntries); - // Rather than sort & fold the 32-byte entries directly, we create a - // vector of indices to entries and sort & fold that instead. - cuIndices.resize(cuEntries.size()); - std::iota(cuIndices.begin(), cuIndices.end(), 0); - llvm::sort(cuIndices, [&](size_t a, size_t b) { - return cuEntries[a].functionAddress < cuEntries[b].functionAddress; + // Sort the entries by address. + llvm::sort(cuEntries, [&](auto &a, auto &b) { + return a.functionAddress < b.functionAddress; }); // Record the ending boundary before we fold the entries. - cueEndBoundary = cuEntries[cuIndices.back()].functionAddress + - cuEntries[cuIndices.back()].functionLength; + cueEndBoundary = + cuEntries.back().functionAddress + cuEntries.back().functionLength; // Fold adjacent entries with matching encoding+personality and without LSDA - // We use three iterators on the same cuIndices to fold in-situ: + // We use three iterators to fold in-situ: // (1) `foldBegin` is the first of a potential sequence of matching entries // (2) `foldEnd` is the first non-matching entry after `foldBegin`. // The semi-open interval [ foldBegin .. foldEnd ) contains a range // entries that can be folded into a single entry and written to ... // (3) `foldWrite` - auto foldWrite = cuIndices.begin(); - for (auto foldBegin = cuIndices.begin(); foldBegin < cuIndices.end();) { + auto foldWrite = cuEntries.begin(); + for (auto foldBegin = cuEntries.begin(); foldBegin != cuEntries.end();) { auto foldEnd = foldBegin; // Common LSDA encodings (e.g. for C++ and Objective-C) contain offsets from // a base address. The base address is normally not contained directly in @@ -503,9 +497,9 @@ void UnwindInfoSectionImpl::finalize() { // directly in the LSDA, two functions at different addresses would // necessarily have different LSDAs, so their CU entries would not have been // folded anyway. - while (++foldEnd < cuIndices.end() && - cuEntries[*foldBegin].encoding == cuEntries[*foldEnd].encoding && - !cuEntries[*foldBegin].lsda && !cuEntries[*foldEnd].lsda && + while (++foldEnd != cuEntries.end() && + foldBegin->encoding == foldEnd->encoding && !foldBegin->lsda && + !foldEnd->lsda && // If we've gotten to this point, we don't have an LSDA, which should // also imply that we don't have a personality function, since in all // likelihood a personality function needs the LSDA to do anything @@ -513,21 +507,20 @@ void UnwindInfoSectionImpl::finalize() { // and no LSDA though (e.g. the C++ personality __gxx_personality_v0 // is just a no-op without LSDA), so we still check for personality // function equivalence to handle that case. - cuEntries[*foldBegin].personality == - cuEntries[*foldEnd].personality && - canFoldEncoding(cuEntries[*foldEnd].encoding)) + foldBegin->personality == foldEnd->personality && + canFoldEncoding(foldEnd->encoding)) ; *foldWrite++ = *foldBegin; foldBegin = foldEnd; } - cuIndices.erase(foldWrite, cuIndices.end()); + cuEntries.erase(foldWrite, cuEntries.end()); encodePersonalities(); // Count frequencies of the folded encodings EncodingMap encodingFrequencies; - for (size_t idx : cuIndices) - encodingFrequencies[cuEntries[idx].encoding]++; + for (const CompactUnwindEntry &cu : cuEntries) + encodingFrequencies[cu.encoding]++; // Make a vector of encodings, sorted by descending frequency for (const auto &frequency : encodingFrequencies) @@ -558,21 +551,19 @@ void UnwindInfoSectionImpl::finalize() { // and 127..255 references a local per-second-level-page table. // First we try the compact format and determine how many entries fit. // If more entries fit in the regular format, we use that. - for (size_t i = 0; i < cuIndices.size();) { - size_t idx = cuIndices[i]; + for (size_t i = 0; i < cuEntries.size();) { secondLevelPages.emplace_back(); SecondLevelPage &page = secondLevelPages.back(); page.entryIndex = i; uint64_t functionAddressMax = - cuEntries[idx].functionAddress + COMPRESSED_ENTRY_FUNC_OFFSET_MASK; + cuEntries[i].functionAddress + COMPRESSED_ENTRY_FUNC_OFFSET_MASK; size_t n = commonEncodings.size(); size_t wordsRemaining = SECOND_LEVEL_PAGE_WORDS - sizeof(unwind_info_compressed_second_level_page_header) / sizeof(uint32_t); - while (wordsRemaining >= 1 && i < cuIndices.size()) { - idx = cuIndices[i]; - const CompactUnwindEntry *cuPtr = &cuEntries[idx]; + while (wordsRemaining >= 1 && i < cuEntries.size()) { + const CompactUnwindEntry *cuPtr = &cuEntries[i]; if (cuPtr->functionAddress >= functionAddressMax) break; if (commonEncodingIndexes.count(cuPtr->encoding) || @@ -593,21 +584,21 @@ void UnwindInfoSectionImpl::finalize() { // If this is not the final page, see if it's possible to fit more entries // by using the regular format. This can happen when there are many unique // encodings, and we saturated the local encoding table early. - if (i < cuIndices.size() && + if (i < cuEntries.size() && page.entryCount < REGULAR_SECOND_LEVEL_ENTRIES_MAX) { page.kind = UNWIND_SECOND_LEVEL_REGULAR; page.entryCount = std::min(REGULAR_SECOND_LEVEL_ENTRIES_MAX, - cuIndices.size() - page.entryIndex); + cuEntries.size() - page.entryIndex); i = page.entryIndex + page.entryCount; } else { page.kind = UNWIND_SECOND_LEVEL_COMPRESSED; } } - for (size_t idx : cuIndices) { - lsdaIndex[idx] = entriesWithLsda.size(); - if (cuEntries[idx].lsda) - entriesWithLsda.push_back(idx); + for (size_t i = 0; i < cuEntries.size(); ++i) { + lsdaIndex[i] = entriesWithLsda.size(); + if (cuEntries[i].lsda) + entriesWithLsda.push_back(i); } // compute size of __TEXT,__unwind_info section @@ -626,7 +617,7 @@ void UnwindInfoSectionImpl::finalize() { // All inputs are relocated and output addresses are known, so write! void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { - assert(!cuIndices.empty() && "call only if there is unwind info"); + assert(!cuEntries.empty() && "call only if there is unwind info"); // section header auto *uip = reinterpret_cast<unwind_info_section_header *>(buf); @@ -660,7 +651,7 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { uint64_t l2PagesOffset = level2PagesOffset; auto *iep = reinterpret_cast<unwind_info_section_header_index_entry *>(i32p); for (const SecondLevelPage &page : secondLevelPages) { - size_t idx = cuIndices[page.entryIndex]; + size_t idx = page.entryIndex; iep->functionOffset = cuEntries[idx].functionAddress - in.header->addr; iep->secondLevelPagesSectionOffset = l2PagesOffset; iep->lsdaIndexArraySectionOffset = @@ -695,7 +686,7 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { for (const SecondLevelPage &page : secondLevelPages) { if (page.kind == UNWIND_SECOND_LEVEL_COMPRESSED) { uintptr_t functionAddressBase = - cuEntries[cuIndices[page.entryIndex]].functionAddress; + cuEntries[page.entryIndex].functionAddress; auto *p2p = reinterpret_cast<unwind_info_compressed_second_level_page_header *>( pp); @@ -708,8 +699,7 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { p2p->encodingsCount = page.localEncodings.size(); auto *ep = reinterpret_cast<uint32_t *>(&p2p[1]); for (size_t i = 0; i < page.entryCount; i++) { - const CompactUnwindEntry &cue = - cuEntries[cuIndices[page.entryIndex + i]]; + const CompactUnwindEntry &cue = cuEntries[page.entryIndex + i]; auto it = commonEncodingIndexes.find(cue.encoding); if (it == commonEncodingIndexes.end()) it = page.localEncodingIndexes.find(cue.encoding); @@ -728,8 +718,7 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { p2p->entryCount = page.entryCount; auto *ep = reinterpret_cast<uint32_t *>(&p2p[1]); for (size_t i = 0; i < page.entryCount; i++) { - const CompactUnwindEntry &cue = - cuEntries[cuIndices[page.entryIndex + i]]; + const CompactUnwindEntry &cue = cuEntries[page.entryIndex + i]; *ep++ = cue.functionAddress; *ep++ = cue.encoding; } diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp index 1180097..1569026 100644 --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -451,6 +451,8 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS, add("-machine:arm64ec"); else if (s == "arm64xpe") add("-machine:arm64x"); + else if (s == "mipspe") + add("-machine:mips"); else error("unknown parameter: -m" + s); } diff --git a/lld/docs/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst index c9cb47f..edbb78ef 100644 --- a/lld/docs/ELF/linker_script.rst +++ b/lld/docs/ELF/linker_script.rst @@ -17,6 +17,25 @@ possible. We reserve the right to make different implementation choices where it is appropriate for LLD. Intentional deviations will be documented in this file. +Linker Script Specification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are two lld options related to setting the linker script, +`--script=<file>` and `--default-script=<file>`. The usage are illustrated below. + +:: + + # `-T` is the alias for `--script` option. + lld -T linker_script.lds + + # `-dT` is the alias for `--default-script` option. + lld -dT linker_script.lds + +When both options are given, `--script=<file>` takes precedence. +The intended use case of `--default-script` is to be used by toolchain +configurations, and users can override the script by specifying `--script` if +needed. + Symbol assignment ~~~~~~~~~~~~~~~~~ diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 29db1cd..60db612 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -52,5 +52,8 @@ MachO Improvements WebAssembly Improvements ------------------------ +* The ``--stack-first`` flag is now enabled by default. The old + behavior can be enabled using ``--no-stack-first``. + Fixes ##### diff --git a/lld/test/COFF/arm64ec-codemap.test b/lld/test/COFF/arm64ec-codemap.test index 0502611..bbc682d 100644 --- a/lld/test/COFF/arm64ec-codemap.test +++ b/lld/test/COFF/arm64ec-codemap.test @@ -7,6 +7,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func-sym2.s -o arm64e RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec.s -o data-sec.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows entry-thunk.s -o entry-thunk.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj @@ -162,15 +163,17 @@ RUN: loadconfig-arm64ec.obj -dll -noentry -merge:test=.testdata -merge: RUN: llvm-readobj --coff-load-config testcm.dll | FileCheck -check-prefix=CODEMAPCM %s CODEMAPCM: CodeMap [ -CODEMAPCM-NEXT: 0x4008 - 0x4016 X64 +CODEMAPCM-NEXT: 0x4000 - 0x4016 X64 CODEMAPCM-NEXT: ] RUN: llvm-objdump -d testcm.dll | FileCheck -check-prefix=DISASMCM %s DISASMCM: Disassembly of section .testdat: DISASMCM-EMPTY: DISASMCM-NEXT: 0000000180004000 <.testdat>: -DISASMCM-NEXT: 180004000: 00000001 udf #0x1 -DISASMCM-NEXT: 180004004: 00000000 udf #0x0 +DISASMCM-NEXT: 180004000: 01 00 addl %eax, (%rax) +DISASMCM-NEXT: 180004002: 00 00 addb %al, (%rax) +DISASMCM-NEXT: 180004004: 00 00 addb %al, (%rax) +DISASMCM-NEXT: 180004006: 00 00 addb %al, (%rax) DISASMCM-NEXT: 180004008: b8 03 00 00 00 movl $0x3, %eax DISASMCM-NEXT: 18000400d: c3 retq DISASMCM-NEXT: 18000400e: 00 00 addb %al, (%rax) @@ -207,6 +210,14 @@ DISASMMS-NEXT: 0000000180006000 <test2>: DISASMMS-NEXT: 180006000: 528000a0 mov w0, #0x5 // =5 DISASMMS-NEXT: 180006004: d65f03c0 ret +Test the code map that includes an ARM64EC function padded by its entry-thunk offset. + +RUN: lld-link -out:testpad.dll -machine:arm64ec entry-thunk.obj loadconfig-arm64ec.obj -dll -noentry -include:func +RUN: llvm-readobj --coff-load-config testpad.dll | FileCheck -check-prefix=CODEMAPPAD %s +CODEMAPPAD: CodeMap [ +CODEMAPPAD: 0x1000 - 0x1010 ARM64EC +CODEMAPPAD-NEXT: ] + #--- arm64-func-sym.s .text @@ -266,3 +277,22 @@ x86_64_func_sym2: .section .empty1, "xr" .section .empty2, "xr" .section .empty3, "xr" + +#--- entry-thunk.s + .section .text,"xr",discard,func + .globl func + .p2align 2, 0x0 +func: + mov w0, #1 + ret + + .section .wowthk$aa,"xr",discard,thunk + .globl thunk + .p2align 2 +thunk: + ret + + .section .hybmp$x,"yi" + .symidx func + .symidx thunk + .word 1 // entry thunk diff --git a/lld/test/COFF/driver.test b/lld/test/COFF/driver.test index 8f58ff4..1c265bf 100644 --- a/lld/test/COFF/driver.test +++ b/lld/test/COFF/driver.test @@ -17,6 +17,9 @@ LIBHELP: OVERVIEW: LLVM Lib # RUN: env LLD_IN_TEST=1 not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s LIBBAD: ignoring /lib since it's not the first argument +# RUN: env LLD_IN_TEST=1 not lld-link /link 2>&1 | FileCheck -check-prefix=LINKBAD %s +LINKBAD: ignoring /link, did you pass it multiple times? + # RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj # RUN: not lld-link /out:/ %t.obj 2>&1 | FileCheck -check-prefix=DIR %s DIR: cannot open output file diff --git a/lld/test/ELF/aarch64-funcinit64-invalid.s b/lld/test/ELF/aarch64-funcinit64-invalid.s new file mode 100644 index 0000000..4577db7 --- /dev/null +++ b/lld/test/ELF/aarch64-funcinit64-invalid.s @@ -0,0 +1,18 @@ +# REQUIRES: aarch64 + +# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck --check-prefix=ERR %s + +.rodata +# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against local symbol +.8byte func@FUNCINIT + +.data +# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against ifunc symbol 'ifunc' +.8byte ifunc@FUNCINIT + +.text +func: +.type ifunc, @gnu_indirect_function +ifunc: +ret diff --git a/lld/test/ELF/aarch64-funcinit64.s b/lld/test/ELF/aarch64-funcinit64.s new file mode 100644 index 0000000..5f2b863 --- /dev/null +++ b/lld/test/ELF/aarch64-funcinit64.s @@ -0,0 +1,19 @@ +# REQUIRES: aarch64 + +# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -s -r %t | FileCheck %s +# RUN: ld.lld %t.o -o %t -pie +# RUN: llvm-readelf -s -r %t | FileCheck %s +# RUN: not ld.lld %t.o -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s + +.data +# CHECK: R_AARCH64_IRELATIVE [[FOO:[0-9a-f]*]] +# ERR: relocation R_AARCH64_FUNCINIT64 cannot be used against preemptible symbol 'foo' +.8byte foo@FUNCINIT + +.text +# CHECK: {{0*}}[[FOO]] {{.*}} foo +.globl foo +foo: +ret diff --git a/lld/test/ELF/dso-undef-extract-lazy.s b/lld/test/ELF/dso-undef-extract-lazy.s index 40b0758..5d92545 100644 --- a/lld/test/ELF/dso-undef-extract-lazy.s +++ b/lld/test/ELF/dso-undef-extract-lazy.s @@ -25,6 +25,11 @@ # CHECK-FETCH: GLOBAL DEFAULT {{[0-9]+}} foo +## Unversioned undefined symbols also extract the archive definitions. +# RUN: yaml2obj %t/ver.yaml -o %t4.so +# RUN: ld.lld %t1.o %t4.so %t2.a -o %t.exe +# RUN: llvm-readelf --dyn-symbols %t.exe | FileCheck %s --check-prefix=CHECK-FETCH + #--- main.s .text .globl _start @@ -38,3 +43,39 @@ foo: #--- shlib.s .global foo + +#--- ver.yaml +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .gnu.version + Type: SHT_GNU_versym + Flags: [ SHF_ALLOC ] + Address: 0x0000000000200210 + AddressAlign: 0x0000000000000002 + EntSize: 0x0000000000000002 +## Test both index 0 and 1 for unversioned undefined symbols. +## https://sourceware.org/PR33577 + Entries: [ 0, 0, 1 ] + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Address: 0x0000000000200250 + AddressAlign: 0x0000000000000004 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: v1 + Hash: 1937 + Flags: 0 + Other: 3 +DynamicSymbols: + - Name: _start + Binding: STB_GLOBAL + - Name: foo + Binding: STB_GLOBAL diff --git a/lld/test/ELF/linkerscript/version-script.s b/lld/test/ELF/linkerscript/version-script.s index 52382ee..6b97fed 100644 --- a/lld/test/ELF/linkerscript/version-script.s +++ b/lld/test/ELF/linkerscript/version-script.s @@ -17,7 +17,7 @@ # CHECK-NEXT: Name: # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Version: 0 # CHECK-NEXT: Name: und # CHECK-NEXT: } # CHECK-NEXT: Symbol { diff --git a/lld/test/ELF/riscv-vendor-relocations.s b/lld/test/ELF/riscv-vendor-relocations.s index b0f3c4a..f121ade 100644 --- a/lld/test/ELF/riscv-vendor-relocations.s +++ b/lld/test/ELF/riscv-vendor-relocations.s @@ -8,12 +8,19 @@ TARGET: nop -.global INVALID_VENDOR +.local INVALID_VENDOR +.local QUALCOMM +.local ANDES .reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0 .reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0 .reloc 1f, R_RISCV_CUSTOM255, TARGET -1: - nop - # CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations # CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET' +.reloc 1f, R_RISCV_VENDOR, QUALCOMM+0 +.reloc 1f, R_RISCV_CUSTOM192, TARGET +# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_QC_ABS20_U against symbol TARGET +.reloc 1f, R_RISCV_VENDOR, ANDES+0 +.reloc 1f, R_RISCV_CUSTOM241, TARGET +# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_NDS_BRANCH_10 against symbol TARGET +1: + nop diff --git a/lld/test/ELF/version-script-extern-undefined.s b/lld/test/ELF/version-script-extern-undefined.s index 3811422..010b4d5 100644 --- a/lld/test/ELF/version-script-extern-undefined.s +++ b/lld/test/ELF/version-script-extern-undefined.s @@ -11,7 +11,7 @@ # CHECK-NEXT: Name: # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Version: 0 # CHECK-NEXT: Name: _Z3abbi # CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/lld/test/MachO/handle-invalid-section-reference-too-big.test b/lld/test/MachO/handle-invalid-section-reference-too-big.test new file mode 100644 index 0000000..1642d63 --- /dev/null +++ b/lld/test/MachO/handle-invalid-section-reference-too-big.test @@ -0,0 +1,128 @@ +# REQUIRES: aarch64 + +## This is a regression test which makes sure that when there is an invalid section index +## associated with a section symbol, the linker does not segfault. + +## Test YAML content was created using the following steps +## 1. Create an object file from the following assembly +## `llvm-mc -filetype=obj -triple=arm64-apple-darwin symbol.s -o symbol.o` +## +## .text +## .section __TEST,__mystuff +## .globl _mysec +## _mysec: +## .byte 0xC3 +## +## 2. Use obj2yaml to convert object file to yaml +## `obj2yaml symbol.o -o symbol.yaml` +## +## 3. Manually set n_sect value of ltmp1 symbol to 10 which is greater than the number of sections 2. +## + +# RUN: yaml2obj %s -o %t +# RUN: not %lld -platform_version macos 10.14 11.0 -arch arm64 %t 2>&1 | FileCheck %s --check-prefix=FATAL + +# FATAL: error: section symbol ltmp0 in {{.*}} has an invalid section index [10] greater than the total number of sections [2] + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x100000C + cpusubtype: 0x0 + filetype: 0x1 + ncmds: 3 + sizeofcmds: 336 + flags: 0x0 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 1 + fileoff: 368 + filesize: 1 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0 + size: 0 + offset: 0x170 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x80000000 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: '' + - sectname: __mystuff + segname: __TEST + addr: 0x0 + size: 1 + offset: 0x170 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: C3 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 376 + nsyms: 3 + stroff: 424 + strsize: 24 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 2 + iextdefsym: 2 + nextdefsym: 1 + iundefsym: 3 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 14 + n_type: 0xE + n_sect: 10 + n_desc: 0 + n_value: 0 + - n_strx: 8 + n_type: 0xE + n_sect: 2 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0xF + n_sect: 2 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _mysec + - ltmp1 + - ltmp0 + - '' + - '' + - '' + - '' +... diff --git a/lld/test/MachO/handle-invalid-section-reference-zero.test b/lld/test/MachO/handle-invalid-section-reference-zero.test new file mode 100644 index 0000000..ab63670 --- /dev/null +++ b/lld/test/MachO/handle-invalid-section-reference-zero.test @@ -0,0 +1,128 @@ +# REQUIRES: aarch64 + +## This is a regression test which makes sure that when there is an invalid section index +## associated with a section symbol, the linker does not segfault. + +## Test YAML content was created using the following steps +## 1. Create an object file from the following assembly +## `llvm-mc -filetype=obj -triple=arm64-apple-darwin symbol.s -o symbol.o` +## +## .text +## .section __TEST,__mystuff +## .globl _mysec +## _mysec: +## .byte 0xC3 +## +## 2. Use obj2yaml to convert object file to yaml +## `obj2yaml symbol.o -o symbol.yaml` +## +## 3. Manually set n_sect value of ltmp1 symbol to 0 instead of 1. +## + +# RUN: yaml2obj %s -o %t +# RUN: not %lld -platform_version macos 10.14 11.0 -arch arm64 %t 2>&1 | FileCheck %s --check-prefix=FATAL + +# FATAL: error: section symbol ltmp0 in {{.*}} has an invalid section index [0] + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x100000C + cpusubtype: 0x0 + filetype: 0x1 + ncmds: 3 + sizeofcmds: 336 + flags: 0x0 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 1 + fileoff: 368 + filesize: 1 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0 + size: 0 + offset: 0x170 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x80000000 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: '' + - sectname: __mystuff + segname: __TEST + addr: 0x0 + size: 1 + offset: 0x170 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: C3 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 376 + nsyms: 3 + stroff: 424 + strsize: 24 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 2 + iextdefsym: 2 + nextdefsym: 1 + iundefsym: 3 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 14 + n_type: 0xE + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 8 + n_type: 0xE + n_sect: 2 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0xF + n_sect: 2 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _mysec + - ltmp1 + - ltmp0 + - '' + - '' + - '' + - '' +... diff --git a/lld/test/MachO/order-file-cstring.s b/lld/test/MachO/order-file-cstring.s index 3c6d2a3..d673430 100644 --- a/lld/test/MachO/order-file-cstring.s +++ b/lld/test/MachO/order-file-cstring.s @@ -4,32 +4,34 @@ # RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/test.s -o %t/test.o # RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/more-cstrings.s -o %t/more-cstrings.o -# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-0 %t/test.o %t/more-cstrings.o +# RUN: %lld -arch arm64 -lSystem -e _main -o %t/test-0 %t/test.o %t/more-cstrings.o # RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SYM # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-0 | FileCheck %s --check-prefix=ORIGIN_SEC -# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-1 %t/test.o %t/more-cstrings.o -order_file %t/ord-1 +# RUN: %lld -arch arm64 -lSystem -e _main -o %t/test-1 %t/test.o %t/more-cstrings.o -order_file %t/ord-1 # RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-1 | FileCheck %s --check-prefix=ONE_SYM # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-1 | FileCheck %s --check-prefix=ONE_SEC +# RUN: %lld --no-deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-1-dup %t/test.o %t/more-cstrings.o -order_file %t/ord-1 +# RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-1-dup | FileCheck %s --check-prefix=ONE_SYM +# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-1-dup | FileCheck %s --check-prefix=ONE_SEC -# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-2 %t/test.o %t/more-cstrings.o -order_file %t/ord-2 +# RUN: %lld -arch arm64 -lSystem -e _main -o %t/test-2 %t/test.o %t/more-cstrings.o -order_file %t/ord-2 # RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-2 | FileCheck %s --check-prefix=TWO_SYM # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-2 | FileCheck %s --check-prefix=TWO_SEC -# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-3 %t/test.o %t/more-cstrings.o -order_file %t/ord-3 +# RUN: %lld -arch arm64 -lSystem -e _main -o %t/test-3 %t/test.o %t/more-cstrings.o -order_file %t/ord-3 # RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-3 | FileCheck %s --check-prefix=THREE_SYM # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-3 | FileCheck %s --check-prefix=THREE_SEC -# RUN: %lld --deduplicate-strings -arch arm64 -lSystem -e _main -o %t/test-4 %t/test.o %t/more-cstrings.o -order_file %t/ord-4 +# RUN: %lld -arch arm64 -lSystem -e _main -o %t/test-4 %t/test.o %t/more-cstrings.o -order_file %t/ord-4 # RUN: llvm-nm --numeric-sort --format=just-symbols %t/test-4 | FileCheck %s --check-prefix=FOUR_SYM # RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC # RUN: llvm-readobj --string-dump=__cstring %t/test-4 | FileCheck %s --check-prefix=FOUR_SEC_ESCAPE - # We expect: -# 1) Covered cstring symbols are reordered -# 2) the rest of the cstring symbols remain original relative order within the cstring section +# 1) Covered cstring symbols to be reordered +# 2) the rest of the cstring symbols remain in the original relative order within the cstring section # ORIGIN_SYM: _local_foo1 # ORIGIN_SYM: _globl_foo2 @@ -58,8 +60,8 @@ CSTR;1496286555 #foo3 CSTR;1343999025 -# ONE_SYM: _globl_foo2 -# ONE_SYM: _local_foo2 +# ONE_SYM-DAG: _globl_foo2 +# ONE_SYM-DAG: _local_foo2 # ONE_SYM: _bar # ONE_SYM: _bar2 # ONE_SYM: _globl_foo3 diff --git a/lld/test/MachO/read-workers.s b/lld/test/MachO/read-workers.s index 294106b..4d2f88c 100644 --- a/lld/test/MachO/read-workers.s +++ b/lld/test/MachO/read-workers.s @@ -1,7 +1,4 @@ # REQUIRES: x86 && thread_support -## Sometimes fails, particularly in an ASAN build, do not run until -## https://github.com/llvm/llvm-project/pull/157917 addresses the cause. -# UNSUPPORTED: target={{.*}} # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o ## A non-negative integer is allowed. diff --git a/lld/test/MachO/set-slop-scale.s b/lld/test/MachO/set-slop-scale.s new file mode 100644 index 0000000..a18acce --- /dev/null +++ b/lld/test/MachO/set-slop-scale.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-darwin %s -o %t.o +# RUN: %lld -o /dev/null %t.o --slop_scale=1 +# RUN: not %lld -o /dev/null %t.o --slop_scale=-1 2>&1 | FileCheck %s +# CHECK: error: --slop_scale=: expected a non-negative integer, but got '-1' + +.text +.global _main +_main: + mov $0, %rax + ret diff --git a/lld/test/MachO/weak-alias-override.s b/lld/test/MachO/weak-alias-override.s new file mode 100644 index 0000000..224ddc4 --- /dev/null +++ b/lld/test/MachO/weak-alias-override.s @@ -0,0 +1,97 @@ +# REQUIRES: x86 +# RUN: rm -rf %t; split-file %s %t +# RUN: mkdir -p %t/bin + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/weak.o %t/weak.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/strong_a.o %t/strong_a.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/strong_b.o %t/strong_b.s + +# --- Test Case 1: No overrides +# RUN: %lld %t/weak.o -o %t/bin/alone -e _s +# RUN: llvm-nm -am %t/bin/alone | FileCheck --check-prefix=NM_ALONE %s + +# NM_ALONE: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_ALONE: [[#P_ADDR]] (__TEXT,__const) weak external _weak_a +# NM_ALONE: [[#P_ADDR]] (__TEXT,__const) weak external _weak_b + +# --- Test Case 2: Override weak_a +# RUN: %lld %t/weak.o %t/strong_a.o -o %t/bin/with_a -e _s +# RUN: llvm-nm -am %t/bin/with_a | FileCheck --check-prefix=NM_WITH_A %s +# RUN: llvm-nm -am %t/bin/with_a | FileCheck --check-prefix=NM_WITH_A_BAD %s + +# NM_WITH_A: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_A: [[#%x, A_ADDR:]] (__TEXT,__const) external _strong_a +# NM_WITH_A: [[#A_ADDR]] (__TEXT,__const) external _weak_a +# NM_WITH_A: [[#P_ADDR]] (__TEXT,__const) weak external _weak_b + +# --- Addresses of _placeholder_int and _strong_a must not match. +# NM_WITH_A_BAD: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_A_BAD-NOT: [[#P_ADDR]] (__TEXT,__const) external _strong_a + +# --- Test Case 3: Override weak_b +# RUN: %lld %t/weak.o %t/strong_b.o -o %t/bin/with_b -e _s +# RUN: llvm-nm -am %t/bin/with_b | FileCheck --check-prefix=NM_WITH_B %s +# RUN: llvm-nm -am %t/bin/with_b | FileCheck --check-prefix=NM_WITH_B_BAD %s + +# NM_WITH_B: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_B: [[#%x, B_ADDR:]] (__TEXT,__const) external _strong_b +# NM_WITH_B: [[#P_ADDR]] (__TEXT,__const) weak external _weak_a +# NM_WITH_B: [[#B_ADDR]] (__TEXT,__const) external _weak_b + +# --- Addresses of _placeholder_int and _strong_a must not match. +# NM_WITH_B_BAD: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_B_BAD-NOT: [[#P_ADDR]] (__TEXT,__const) external _strong_b + +# --- Test Case 4: Override weak_a and weak_b +# RUN: %lld %t/weak.o %t/strong_a.o %t/strong_b.o -o %t/bin/with_ab -e _s +# RUN: llvm-nm -am %t/bin/with_ab | FileCheck --check-prefix=NM_WITH_AB %s +# RUN: llvm-nm -am %t/bin/with_ab | FileCheck --check-prefix=NM_WITH_AB_BAD %s + +# NM_WITH_AB: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_AB: [[#%x, A_ADDR:]] (__TEXT,__const) external _strong_a +# NM_WITH_AB: [[#%x, B_ADDR:]] (__TEXT,__const) external _strong_b +# NM_WITH_AB: [[#A_ADDR]] (__TEXT,__const) external _weak_a +# NM_WITH_AB: [[#B_ADDR]] (__TEXT,__const) external _weak_b + +# --- Addresses of _placeholder_int, _strong_a, and _strong_b must all be distinct +# NM_WITH_AB_BAD: [[#%x, P_ADDR:]] (__TEXT,__const) weak external _placeholder_int +# NM_WITH_AB_BAD-NOT: [[#P_ADDR]] (__TEXT,__const) external _strong_a +# NM_WITH_AB_BAD-NOT: [[#P_ADDR]] (__TEXT,__const) external _strong_b + +#--- weak.s +.section __TEXT,__const +.globl _placeholder_int +.weak_definition _placeholder_int +_placeholder_int: + .long 0 + +.globl _weak_a +.set _weak_a, _placeholder_int +.weak_definition _weak_a + +.globl _weak_b +.set _weak_b, _placeholder_int +.weak_definition _weak_b + +.globl _s +_s: + .quad _weak_a + .quad _weak_b + +#--- strong_a.s +.section __TEXT,__const +.globl _strong_a +_strong_a: + .long 1 + +.globl _weak_a +_weak_a = _strong_a + +#--- strong_b.s +.section __TEXT,__const +.globl _strong_b +_strong_b: + .long 2 + +.globl _weak_b +_weak_b = _strong_b diff --git a/lld/test/MachO/x86-64-relocs.s b/lld/test/MachO/x86-64-relocs.s index 5303948..d29f689 100644 --- a/lld/test/MachO/x86-64-relocs.s +++ b/lld/test/MachO/x86-64-relocs.s @@ -4,6 +4,7 @@ # RUN: llvm-objdump --no-print-imm-hex --section-headers --syms -d %t | FileCheck %s # CHECK-LABEL: Sections: +# CHECK: __branch_target {{[0-9a-z]+}} [[#%x, BRANCH_SECT:]] # CHECK: __data {{[0-9a-z]+}} [[#%x, DATA_ADDR:]] # CHECK-LABEL: SYMBOL TABLE: @@ -12,10 +13,18 @@ # CHECK-LABEL: <_main>: ## Test X86_64_RELOC_BRANCH +## Test symbol (extern) relocations first (most common case) # CHECK: callq 0x[[#%x, F_ADDR]] <_f> # CHECK: jrcxz 0x[[#%x, F_ADDR]] <_f> # CHECK: callq 0x[[#%x, G_ADDR]] <_g> # CHECK: jrcxz 0x[[#%x, G_ADDR]] <_g> +## Test section (local) BRANCH relocations +# CHECK: callq 0x[[#%x, BRANCH_SECT]] +## NOTE: ld64 rejects 1-byte local branch relocations as unsupported, but it +## doesn't take any extra code for us to support it +# CHECK: jrcxz 0x[[#%x, BRANCH_SECT]] + +# CHECK-LABEL: <_f>: ## Test extern (symbol) X86_64_RELOC_SIGNED # CHECK: leaq [[#%u, LOCAL_OFF:]](%rip), %rsi # CHECK-NEXT: [[#%x, DATA_ADDR - LOCAL_OFF]] @@ -33,9 +42,12 @@ _main: callq _f # X86_64_RELOC_BRANCH with r_length=2 jrcxz _f # X86_64_RELOC_BRANCH with r_length=0 - # test negative addends + # Test negative addends callq _f - 1 jrcxz _f - 1 + # Test section relocations + callq L_.branch_target + jrcxz L_.branch_target mov $0, %rax ret @@ -48,6 +60,10 @@ _f: movq L_.ptr_1(%rip), %rsi ret +.section __TEXT,__branch_target +L_.branch_target: + ret + .data ## References to this generate a symbol relocation _local: diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test index 47809d8..ef03c01 100644 --- a/lld/test/MinGW/driver.test +++ b/lld/test/MinGW/driver.test @@ -37,6 +37,12 @@ ARM64X-SAME: -machine:arm64x ARM64X-SAME: -alternatename:__image_base__=__ImageBase ARM64X-SAME: foo.o +RUN: ld.lld -### foo.o -m mipspe 2>&1 | FileCheck -check-prefix=MIPS %s +MIPS: -out:a.exe +MIPS-SAME: -machine:mips +MIPS-SAME: -alternatename:__image_base__=__ImageBase +MIPS-SAME: foo.o + RUN: ld.lld -### foo.o -m i386pep -shared 2>&1 | FileCheck -check-prefix=SHARED %s RUN: ld.lld -### foo.o -m i386pep --shared 2>&1 | FileCheck -check-prefix=SHARED %s RUN: ld.lld -### foo.o -m i386pep --dll 2>&1 | FileCheck -check-prefix=SHARED %s diff --git a/lld/test/wasm/alias.s b/lld/test/wasm/alias.s index 0bb035b..83f40a8 100644 --- a/lld/test/wasm/alias.s +++ b/lld/test/wasm/alias.s @@ -24,7 +24,7 @@ _start: # CHECK-NEXT: FunctionTypes: [ 0 ] # CHECK-NEXT: - Type: MEMORY # CHECK-NEXT: Memories: -# CHECK-NEXT: - Minimum: 0x2 +# CHECK-NEXT: - Minimum: 0x1 # CHECK-NEXT: - Type: GLOBAL # CHECK-NEXT: Globals: # CHECK-NEXT: - Index: 0 @@ -32,7 +32,7 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/bss-only.s b/lld/test/wasm/bss-only.s index 1c0500f..bec7592 100644 --- a/lld/test/wasm/bss-only.s +++ b/lld/test/wasm/bss-only.s @@ -26,13 +26,13 @@ b: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 67568 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 2028 +# CHECK-NEXT: Value: 66540 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/build-id.test b/lld/test/wasm/build-id.test index dd6e223710..5fafd21 100644 --- a/lld/test/wasm/build-id.test +++ b/lld/test/wasm/build-id.test @@ -43,12 +43,12 @@ foo: # DEFAULT: Contents of section build_id: -# DEFAULT-NEXT: 0079 10299168 1e3c845a 3c8f80ae 2f16cc22 .).h.<.Z<.../.." -# DEFAULT-NEXT: 0089 2d +# DEFAULT-NEXT: 0079 103f86e6 3bb81959 2e99ffa9 acfed331 .?..;..Y.......1 +# DEFAULT-NEXT: 0089 3a # SHA1: Contents of section build_id: -# SHA1-NEXT: 0079 145abdda 387a9bc4 e3aed3c3 3319cd37 .Z..8z......3..7 -# SHA1-NEXT: 0089 0212237c e4 ..#|. +# SHA1-NEXT: 0079 1410ade4 e75d1c9d 71023465 03b7572f .....]..q.4e..W/ +# SHA1-NEXT: 0089 c06c5ae0 74 .lZ.t # UUID: Contents of section build_id: # UUID-NEXT: 0079 10 diff --git a/lld/test/wasm/call-indirect.s b/lld/test/wasm/call-indirect.s index 7bf39a9..64eaa59 100644 --- a/lld/test/wasm/call-indirect.s +++ b/lld/test/wasm/call-indirect.s @@ -82,13 +82,13 @@ indirect_func: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66576 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1032 +# CHECK-NEXT: Value: 65544 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory @@ -125,23 +125,23 @@ indirect_func: # CHECK-NEXT: Body: 42010B # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Locals: -# CHECK-NEXT: Body: 410028028088808000118080808000001A410028028488808000118180808000001A0B +# CHECK-NEXT: Body: 410028028080848000118080808000001A410028028480848000118180808000001A0B # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Locals: # CHECK-NEXT: Body: 41020B # CHECK-NEXT: - Index: 3 # CHECK-NEXT: Locals: -# CHECK-NEXT: Body: 410028028888808000118180808000001A0B +# CHECK-NEXT: Body: 410028028880848000118180808000001A0B # CHECK-NEXT: - Index: 4 # CHECK-NEXT: Locals: # CHECK-NEXT: Body: 42012000118280808000001A0B # CHECK-NEXT: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: '010000000200000002000000' # CHECK-NEXT: - Type: CUSTOM # CHECK-NEXT: Name: name diff --git a/lld/test/wasm/comdats.ll b/lld/test/wasm/comdats.ll index 2dd687f..1662a98 100644 --- a/lld/test/wasm/comdats.ll +++ b/lld/test/wasm/comdats.ll @@ -23,13 +23,13 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory @@ -69,7 +69,7 @@ entry: ; CHECK-NEXT: Body: 1080808080001082808080001A0B ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4180888080000B +; CHECK-NEXT: Body: 4180808480000B ; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 0B @@ -81,9 +81,9 @@ entry: ; CHECK-NEXT: Body: 4181808080000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '616263' diff --git a/lld/test/wasm/compress-relocs.s b/lld/test/wasm/compress-relocs.s index 41d4ff5..37f1b3b 100644 --- a/lld/test/wasm/compress-relocs.s +++ b/lld/test/wasm/compress-relocs.s @@ -47,16 +47,16 @@ test_memory_and_indirect_call_relocs: end_function # CHECK: test_memory_and_indirect_call_relocs -# CHECK: 41 90 88 80 80 00 i32.const 1040 +# CHECK: 41 90 80 84 80 00 i32.const 65552 # CHECK: 11 80 80 80 80 00 80 80 80 80 00 call_indirect 0 -# CHECK: 28 02 94 88 80 80 00 i32.load 1044 +# CHECK: 28 02 94 80 84 80 00 i32.load 65556 # CHECK: 11 81 80 80 80 00 80 80 80 80 00 call_indirect 1 # CHECK: 41 81 80 80 80 00 i32.const 1 # CHECK: 11 80 80 80 80 00 80 80 80 80 00 call_indirect 0 # COMPRESS: test_memory_and_indirect_call_relocs -# COMPRESS: 41 90 08 i32.const 1040 +# COMPRESS: 41 90 80 04 i32.const 65552 # COMPRESS: 11 00 00 call_indirect 0 -# COMPRESS: 28 02 94 08 i32.load 1044 +# COMPRESS: 28 02 94 80 04 i32.load 65556 # COMPRESS: 11 01 00 call_indirect 1 # COMPRESS: 41 01 i32.const 1 # COMPRESS: 11 00 00 call_indirect 0 @@ -91,11 +91,11 @@ test_relative_relocs: end_function # CHECK: test_relative_relocs -# CHECK: 41 90 88 80 80 00 i32.const 1040 +# CHECK: 41 90 80 84 80 00 i32.const 65552 # CHECK: 41 81 80 80 80 00 i32.const 1 # CHECK: 41 83 80 80 80 00 i32.const 3 # COMPRESS: test_relative_relocs -# COMPRESS: 41 90 08 i32.const 1040 +# COMPRESS: 41 90 80 04 i32.const 65552 # COMPRESS: 41 01 i32.const 1 # COMPRESS: 41 03 i32.const 3 diff --git a/lld/test/wasm/compress-relocs64.s b/lld/test/wasm/compress-relocs64.s index 44e7a08..f3ff646 100644 --- a/lld/test/wasm/compress-relocs64.s +++ b/lld/test/wasm/compress-relocs64.s @@ -36,12 +36,12 @@ test_memory_and_indirect_call_relocs: end_function # CHECK: test_memory_and_indirect_call_relocs -# CHECK: 42 90 88 80 80 80 80 80 80 80 00 i64.const 1040 -# CHECK: 29 03 98 88 80 80 80 80 80 80 80 00 i64.load 1048 +# CHECK: 42 90 80 84 80 80 80 80 80 80 00 i64.const 65552 +# CHECK: 29 03 98 80 84 80 80 80 80 80 80 00 i64.load 65560 # CHECK: 42 81 80 80 80 80 80 80 80 80 00 i64.const 1 # COMPRESS: test_memory_and_indirect_call_relocs -# COMPRESS: 42 90 08 i64.const 1040 -# COMPRESS: 29 03 98 08 i64.load 1048 +# COMPRESS: 42 90 80 04 i64.const 65552 +# COMPRESS: 29 03 98 80 04 i64.load 65560 # COMPRESS: 42 01 i64.const 1 .globl test_relative_relocs @@ -56,11 +56,11 @@ test_relative_relocs: end_function # CHECK: test_relative_relocs -# CHECK: 42 90 88 80 80 80 80 80 80 80 00 i64.const 1040 +# CHECK: 42 90 80 84 80 80 80 80 80 80 00 i64.const 65552 # CHECK: 42 81 80 80 80 80 80 80 80 80 00 i64.const 1 # CHECK: 42 83 80 80 80 80 80 80 80 80 00 i64.const 3 # COMPRESS: test_relative_relocs -# COMPRESS: 42 90 08 i64.const 1040 +# COMPRESS: 42 90 80 04 i64.const 65552 # COMPRESS: 42 01 i64.const 1 # COMPRESS: 42 03 i64.const 3 diff --git a/lld/test/wasm/custom-section-name.ll b/lld/test/wasm/custom-section-name.ll index 8799fbf..89cb72f 100644 --- a/lld/test/wasm/custom-section-name.ll +++ b/lld/test/wasm/custom-section-name.ll @@ -16,29 +16,29 @@ target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '00000000' -; CHECK-NEXT: - SectionOffset: 17 +; CHECK-NEXT: - SectionOffset: 19 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: Value: 65540 ; CHECK-NEXT: Content: 2A000000 -; CHECK-NEXT: - SectionOffset: 27 +; CHECK-NEXT: - SectionOffset: 30 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1032 +; CHECK-NEXT: Value: 65544 ; CHECK-NEXT: Content: '07000000' -; BSS-NEXT: - SectionOffset: 37 +; BSS-NEXT: - SectionOffset: 41 ; BSS-NEXT: InitFlags: 0 ; BSS-NEXT: Offset: ; BSS-NEXT: Opcode: I32_CONST -; BSS-NEXT: Value: 1036 +; BSS-NEXT: Value: 65548 ; BSS-NEXT: Content: '00000000' ; NO-BSS-NOT: - SectionOffset: diff --git a/lld/test/wasm/data-layout.s b/lld/test/wasm/data-layout.s index a68bc03..8df834d 100644 --- a/lld/test/wasm/data-layout.s +++ b/lld/test/wasm/data-layout.s @@ -63,33 +63,33 @@ local_struct_internal_ptr: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: [[PTR]]_CONST -# CHECK-NEXT: Value: 66624 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: [[PTR]] # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: [[PTR]]_CONST -# CHECK-NEXT: Value: 1080 +# CHECK-NEXT: Value: 65592 # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Type: [[PTR]] # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: [[PTR]]_CONST -# CHECK-NEXT: Value: 66624 +# CHECK-NEXT: Value: 65600 # CHECK: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: [[PTR]]_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: 68656C6C6F0A00 -# CHECK-NEXT: - SectionOffset: 20 +# CHECK-NEXT: - SectionOffset: 22 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: [[PTR]]_CONST -# CHECK-NEXT: Value: 1040 +# CHECK-NEXT: Value: 65552 # RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \ diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll index e6f3c5e..34c49e8 100644 --- a/lld/test/wasm/data-segment-merging.ll +++ b/lld/test/wasm/data-segment-merging.ll @@ -15,11 +15,11 @@ ; MERGE-LABEL: - Type: DATA ; MERGE-NEXT: Segments: -; MERGE-NEXT: - SectionOffset: 7 +; MERGE-NEXT: - SectionOffset: 8 ; MERGE-NEXT: InitFlags: 0 ; MERGE-NEXT: Offset: ; MERGE: Content: 636F6E7374616E74000000002B -; MERGE-NEXT: - SectionOffset: 26 +; MERGE-NEXT: - SectionOffset: 28 ; MERGE-NEXT: InitFlags: 0 ; MERGE-NEXT: Offset: ; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 @@ -41,27 +41,27 @@ ; SEPARATE-NOT: DATACOUNT ; SEPARATE-LABEL: - Type: DATA ; SEPARATE-NEXT: Segments: -; SEPARATE-NEXT: - SectionOffset: 7 +; SEPARATE-NEXT: - SectionOffset: 8 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: 636F6E7374616E7400 -; SEPARATE-NEXT: - SectionOffset: 22 +; SEPARATE-NEXT: - SectionOffset: 24 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: 2B -; SEPARATE-NEXT: - SectionOffset: 29 +; SEPARATE-NEXT: - SectionOffset: 32 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: 68656C6C6F00 -; SEPARATE-NEXT: - SectionOffset: 41 +; SEPARATE-NEXT: - SectionOffset: 45 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: 676F6F6462796500 -; SEPARATE-NEXT: - SectionOffset: 55 +; SEPARATE-NEXT: - SectionOffset: 60 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: '776861746576657200' -; SEPARATE-NEXT: - SectionOffset: 70 +; SEPARATE-NEXT: - SectionOffset: 76 ; SEPARATE-NEXT: InitFlags: 0 ; SEPARATE-NEXT: Offset: ; SEPARATE: Content: 2A000000 diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll index 6c401c4..237f428 100644 --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -61,20 +61,20 @@ ; ACTIVE-NEXT: Body: 0B ; ACTIVE-NEXT: - Type: DATA ; ACTIVE-NEXT: Segments: -; ACTIVE-NEXT: - SectionOffset: 7 +; ACTIVE-NEXT: - SectionOffset: 8 ; ACTIVE-NEXT: InitFlags: 0 ; ACTIVE-NEXT: Offset: ; ACTIVE32-NEXT: Opcode: I32_CONST ; ACTIVE64-NEXT: Opcode: I64_CONST -; ACTIVE-NEXT: Value: 1024 +; ACTIVE-NEXT: Value: 65536 ; ACTIVE-NEXT: Content: 636F6E7374616E74000000002B -; ACTIVE-NEXT: - SectionOffset: 26 +; ACTIVE-NEXT: - SectionOffset: 28 ; ACTIVE-NEXT: InitFlags: 0 ; ACTIVE-NEXT: Offset: ; ACTIVE32-NEXT: Opcode: I32_CONST ; ACTIVE64-NEXT: Opcode: I64_CONST -; ACTIVE-NEXT: Value: 1040 -; ACTIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000 +; ACTIVE-NEXT: Value: 65552 +; ACTIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A00000063000000 ; ACTIVE-NEXT: - Type: CUSTOM ; ACTIVE-NEXT: Name: name ; ACTIVE-NEXT: FunctionNames: @@ -201,7 +201,7 @@ ; DIS-NEXT: block ; DIS-NEXT: block -; NOPIC-DIS-NEXT: [[PTR]].const 11064 +; NOPIC-DIS-NEXT: [[PTR]].const 75576 ; PIC-DIS-NEXT: local.get 0 ; DIS-NEXT: i32.const 0 @@ -211,8 +211,8 @@ ; DIS-NEXT: # 2: down to label0 ; DIS-NEXT: end -; NOPIC-DIS-NEXT: [[PTR]].const 1024 -; NOPIC-DIS-NEXT: [[PTR]].const 1024 +; NOPIC-DIS-NEXT: [[PTR]].const 65536 +; NOPIC-DIS-NEXT: [[PTR]].const 65536 ; NOPIC-DIS-NEXT: global.set 1 ; PIC-DIS-NEXT: [[PTR]].const 0 ; PIC-DIS-NEXT: global.get 1 @@ -224,7 +224,7 @@ ; DIS-NEXT: i32.const 4 ; DIS-NEXT: memory.init 0, 0 -; NOPIC-DIS-NEXT: [[PTR]].const 1028 +; NOPIC-DIS-NEXT: [[PTR]].const 65540 ; PIC-DIS-NEXT: [[PTR]].const 4 ; PIC-DIS-NEXT: global.get 1 ; PIC-DIS-NEXT: [[PTR]].add @@ -233,7 +233,7 @@ ; DIS-NEXT: i32.const 13 ; DIS-NEXT: memory.init 1, 0 -; NOPIC-DIS-NEXT: [[PTR]].const 1044 +; NOPIC-DIS-NEXT: [[PTR]].const 65556 ; PIC-DIS-NEXT: [[PTR]].const 20 ; PIC-DIS-NEXT: global.get 1 ; PIC-DIS-NEXT: [[PTR]].add @@ -241,7 +241,7 @@ ; DIS-NEXT: i32.const 0 ; DIS-NEXT: i32.const 20 ; DIS-NEXT: memory.init 2, 0 -; NOPIC-DIS-NEXT: [[PTR]].const 1064 +; NOPIC-DIS-NEXT: [[PTR]].const 65576 ; PIC-DIS-NEXT: [[PTR]].const 40 ; PIC-DIS-NEXT: global.get 1 ; PIC-DIS-NEXT: [[PTR]].add @@ -249,13 +249,13 @@ ; DIS-NEXT: [[PTR]].const 10000 ; DIS-NEXT: memory.fill 0 -; NOPIC-DIS-NEXT: [[PTR]].const 11064 +; NOPIC-DIS-NEXT: [[PTR]].const 75576 ; PIC-DIS-NEXT: local.get 0 ; DIS-NEXT: i32.const 2 ; DIS-NEXT: i32.atomic.store 0 -; NOPIC-DIS-NEXT: [[PTR]].const 11064 +; NOPIC-DIS-NEXT: [[PTR]].const 75576 ; PIC-DIS-NEXT: local.get 0 ; DIS-NEXT: i32.const -1 @@ -264,7 +264,7 @@ ; DIS-NEXT: br 1 # 1: down to label1 ; DIS-NEXT: end -; NOPIC-DIS-NEXT: [[PTR]].const 11064 +; NOPIC-DIS-NEXT: [[PTR]].const 75576 ; PIC-DIS-NEXT: local.get 0 ; DIS-NEXT: i32.const 1 diff --git a/lld/test/wasm/debuginfo.test b/lld/test/wasm/debuginfo.test index 9cb1cc3..7e6bd51 100644 --- a/lld/test/wasm/debuginfo.test +++ b/lld/test/wasm/debuginfo.test @@ -50,7 +50,7 @@ CHECK-NEXT: DW_AT_type (0x000000ac "int[2]") CHECK-NEXT: DW_AT_external (true) CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c") CHECK-NEXT: DW_AT_decl_line (1) -CHECK: DW_AT_location (DW_OP_addr 0x400) +CHECK: DW_AT_location (DW_OP_addr 0x10000) CHECK: DW_TAG_array_type diff --git a/lld/test/wasm/dylink-non-pie.s b/lld/test/wasm/dylink-non-pie.s index 3157b8c..fddfddb 100755 --- a/lld/test/wasm/dylink-non-pie.s +++ b/lld/test/wasm/dylink-non-pie.s @@ -32,7 +32,7 @@ f_p: # DIS: <__wasm_apply_data_relocs>: # DIS-EMPTY: -# DIS-NEXT: i32.const 1024 +# DIS-NEXT: i32.const 65536 # DIS-NEXT: global.get 0 # DIS-NEXT: i32.store 0 # DIS-NEXT: end diff --git a/lld/test/wasm/emit-relocs.s b/lld/test/wasm/emit-relocs.s index 385344c..3df345c 100644 --- a/lld/test/wasm/emit-relocs.s +++ b/lld/test/wasm/emit-relocs.s @@ -41,11 +41,11 @@ foo: # CHECK: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: '00000000' # There should be a single relocation in this section (just the live symbol) @@ -75,5 +75,5 @@ foo: # CHECK-NEXT: Kind: DATA # CHECK-NEXT: Name: __stack_low # CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN, ABSOLUTE ] -# CHECK-NEXT: Offset: 1040 # CHECK-NEXT: Size: 0 +# CHECK-NEXT: - Index: 3 diff --git a/lld/test/wasm/externref.s b/lld/test/wasm/externref.s index ffc63a6..1443e5f 100644 --- a/lld/test/wasm/externref.s +++ b/lld/test/wasm/externref.s @@ -35,7 +35,7 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: EXTERNREF # CHECK-NEXT: Mutable: true diff --git a/lld/test/wasm/gc-sections.ll b/lld/test/wasm/gc-sections.ll index e709ab7..69d7ed2 100644 --- a/lld/test/wasm/gc-sections.ll +++ b/lld/test/wasm/gc-sections.ll @@ -57,7 +57,7 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I64 ; CHECK-NEXT: Mutable: true @@ -67,11 +67,11 @@ entry: ; CHECK: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '02000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name @@ -123,7 +123,7 @@ entry: ; NO-GC-NEXT: Mutable: true ; NO-GC-NEXT: InitExpr: ; NO-GC-NEXT: Opcode: I32_CONST -; NO-GC-NEXT: Value: 66576 +; NO-GC-NEXT: Value: 65536 ; NO-GC-NEXT: - Index: 1 ; NO-GC-NEXT: Type: I64 ; NO-GC-NEXT: Mutable: true @@ -139,11 +139,11 @@ entry: ; NO-GC: - Type: DATA ; NO-GC-NEXT: Segments: -; NO-GC-NEXT: - SectionOffset: 7 +; NO-GC-NEXT: - SectionOffset: 8 ; NO-GC-NEXT: InitFlags: 0 ; NO-GC-NEXT: Offset: ; NO-GC-NEXT: Opcode: I32_CONST -; NO-GC-NEXT: Value: 1024 +; NO-GC-NEXT: Value: 65536 ; NO-GC-NEXT: Content: '010000000000000002000000' ; NO-GC-NEXT: - Type: CUSTOM ; NO-GC-NEXT: Name: name diff --git a/lld/test/wasm/global-base.test b/lld/test/wasm/global-base.test index 0e65f0c..e84b8ec 100644 --- a/lld/test/wasm/global-base.test +++ b/lld/test/wasm/global-base.test @@ -19,19 +19,19 @@ CHECK-1024-NEXT: Type: I32 CHECK-1024-NEXT: Mutable: true CHECK-1024-NEXT: InitExpr: CHECK-1024-NEXT: Opcode: I32_CONST -CHECK-1024-NEXT: Value: 66560 +CHECK-1024-NEXT: Value: 65536 CHECK-1024-NEXT: - Index: 1 CHECK-1024-NEXT: Type: I32 CHECK-1024-NEXT: Mutable: false CHECK-1024-NEXT: InitExpr: CHECK-1024-NEXT: Opcode: I32_CONST -CHECK-1024-NEXT: Value: 1024 +CHECK-1024-NEXT: Value: 65536 CHECK-1024-NEXT: - Index: 2 CHECK-1024-NEXT: Type: I32 CHECK-1024-NEXT: Mutable: false CHECK-1024-NEXT: InitExpr: CHECK-1024-NEXT: Opcode: I32_CONST -CHECK-1024-NEXT: Value: 1024 +CHECK-1024-NEXT: Value: 65536 CHECK-1024: - Type: EXPORT CHECK-1024: - Name: __data_end @@ -50,7 +50,7 @@ CHECK-16777216-NEXT: Type: I32 CHECK-16777216-NEXT: Mutable: true CHECK-16777216-NEXT: InitExpr: CHECK-16777216-NEXT: Opcode: I32_CONST -CHECK-16777216-NEXT: Value: 16842752 +CHECK-16777216-NEXT: Value: 65536 CHECK-16777216-NEXT: - Index: 1 CHECK-16777216-NEXT: Type: I32 CHECK-16777216-NEXT: Mutable: false diff --git a/lld/test/wasm/globals.s b/lld/test/wasm/globals.s index 6e049e1..47d9ba8 100644 --- a/lld/test/wasm/globals.s +++ b/lld/test/wasm/globals.s @@ -42,7 +42,7 @@ immutable_global: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false diff --git a/lld/test/wasm/import-memory.test b/lld/test/wasm/import-memory.test index dd7066d..9b8148e 100644 --- a/lld/test/wasm/import-memory.test +++ b/lld/test/wasm/import-memory.test @@ -10,7 +10,7 @@ # CHECK-NEXT: Field: memory # CHECK-NEXT: Kind: MEMORY # CHECK-NEXT: Memory: -# CHECK-NEXT: Minimum: 0x2 +# CHECK-NEXT: Minimum: 0x1 # CHECK-NEXT: - Type: diff --git a/lld/test/wasm/init-fini.ll b/lld/test/wasm/init-fini.ll index ef2f41f..7471ebb 100644 --- a/lld/test/wasm/init-fini.ll +++ b/lld/test/wasm/init-fini.ll @@ -78,7 +78,7 @@ entry: ; CHECK-NEXT: Body: 10041005100A100F1012100F10141004100C100F10161002100E0B ; CHECK: - Index: 22 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 02404186808080004100418088808000108080808000450D00000B0B +; CHECK-NEXT: Body: 02404186808080004100418080848000108080808000450D00000B0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: diff --git a/lld/test/wasm/large-memory.test b/lld/test/wasm/large-memory.test index 5b737e4..a2888c6 100644 --- a/lld/test/wasm/large-memory.test +++ b/lld/test/wasm/large-memory.test @@ -12,7 +12,7 @@ RUN: obj2yaml %t2.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-4G CHECK: - Type: MEMORY CHECK-NEXT: Memories: CHECK-NEXT: - Flags: [ HAS_MAX ] -CHECK-NEXT: Minimum: 0x2 +CHECK-NEXT: Minimum: 0x1 CHECK-2G-NEXT: Maximum: 0x8000 CHECK-4G-NEXT: Maximum: 0x10000 diff --git a/lld/test/wasm/local-symbols.ll b/lld/test/wasm/local-symbols.ll index 8faee64..6c639a8 100644 --- a/lld/test/wasm/local-symbols.ll +++ b/lld/test/wasm/local-symbols.ll @@ -45,13 +45,13 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory @@ -67,17 +67,17 @@ entry: ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4100280284888080000B +; CHECK-NEXT: Body: 4100280284808480000B ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 1080808080001A0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '0100000003000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test index 5c3135a..88819b2 100644 --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -26,7 +26,7 @@ ; CHECK-NEXT: Maximum: 0x7 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: -; CHECK-NEXT: - Minimum: 0x2 +; CHECK-NEXT: - Minimum: 0x2 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: ; CHECK-NEXT: - Index: 0 @@ -34,19 +34,19 @@ ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66592 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: Value: 65540 ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1036 +; CHECK-NEXT: Value: 65548 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory @@ -119,13 +119,13 @@ ; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4180888080000B +; CHECK-NEXT: Body: 4180808480000B ; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4184888080000B +; CHECK-NEXT: Body: 4184808480000B ; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4188888080000B +; CHECK-NEXT: Body: 4188808480000B ; CHECK-NEXT: - Index: 6 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4181808080000B @@ -146,13 +146,13 @@ ; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: - Index: 12 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 418C888080000B +; CHECK-NEXT: Body: 418C808480000B ; CHECK-NEXT: - Index: 13 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4190888080000B +; CHECK-NEXT: Body: 4190808480000B ; CHECK-NEXT: - Index: 14 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 4194888080000B +; CHECK-NEXT: Body: 4194808480000B ; CHECK-NEXT: - Index: 15 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4184808080000B @@ -164,11 +164,11 @@ ; CHECK-NEXT: Body: 4186808080000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '010000000100000001000000010000000100000001000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name diff --git a/lld/test/wasm/lto/tls.ll b/lld/test/wasm/lto/tls.ll index b61edfb..9c1642e 100644 --- a/lld/test/wasm/lto/tls.ll +++ b/lld/test/wasm/lto/tls.ll @@ -30,13 +30,13 @@ attributes #0 = { noinline nounwind optnone "target-features"="+atomics,+bulk-me ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK: GlobalNames: ; CHECK-NEXT: - Index: 0 diff --git a/lld/test/wasm/lto/used.ll b/lld/test/wasm/lto/used.ll index a185103..dd36259 100644 --- a/lld/test/wasm/lto/used.ll +++ b/lld/test/wasm/lto/used.ll @@ -26,11 +26,11 @@ return: ; CHECK: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: '01000000' ; CHECK: - Type: CUSTOM diff --git a/lld/test/wasm/map-file.s b/lld/test/wasm/map-file.s index 2757f50..380ab57 100644 --- a/lld/test/wasm/map-file.s +++ b/lld/test/wasm/map-file.s @@ -59,15 +59,15 @@ somezeroes: # CHECK-NEXT: - 66 b write_global # CHECK-NEXT: - 71 f {{.*}}{{/|\\}}map-file.s.tmp1.o:(_start) # CHECK-NEXT: - 71 f _start -# CHECK-NEXT: - 82 11 DATA -# CHECK-NEXT: 400 83 8 .data -# CHECK-NEXT: 400 89 8 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) -# CHECK-NEXT: 400 89 8 somedata -# CHECK-NEXT: 408 82 4 .bss -# CHECK-NEXT: 408 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes) -# CHECK-NEXT: 408 0 4 somezeroes -# CHECK-NEXT: - 93 12 CUSTOM(.debug_info) -# CHECK-NEXT: - a5 61 CUSTOM(name) +# CHECK-NEXT: - 82 12 DATA +# CHECK-NEXT: 10000 83 8 .data +# CHECK-NEXT: 10000 8a 8 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) +# CHECK-NEXT: 10000 8a 8 somedata +# CHECK-NEXT: 10008 82 4 .bss +# CHECK-NEXT: 10008 0 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.bss.somezeroes) +# CHECK-NEXT: 10008 0 4 somezeroes +# CHECK-NEXT: - 94 12 CUSTOM(.debug_info) +# CHECK-NEXT: - a6 61 CUSTOM(name) # RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \ # RUN: | FileCheck -check-prefix=FAIL %s diff --git a/lld/test/wasm/memory-naming.test b/lld/test/wasm/memory-naming.test index 766d9cd5..66143c3 100644 --- a/lld/test/wasm/memory-naming.test +++ b/lld/test/wasm/memory-naming.test @@ -57,7 +57,7 @@ # CHECK-IMPORT-NEXT: Field: bar # CHECK-IMPORT-NEXT: Kind: MEMORY # CHECK-IMPORT-NEXT: Memory: -# CHECK-IMPORT-NEXT: Minimum: 0x2 +# CHECK-IMPORT-NEXT: Minimum: 0x1 # CHECK-IMPORT: - Type: EXPORT # CHECK-IMPORT-NEXT: Exports: # CHECK-IMPORT-NEXT: - Name: _start @@ -77,7 +77,7 @@ # CHECK-IMPORT-DEFAULT-NEXT: Field: foo # CHECK-IMPORT-DEFAULT-NEXT: Kind: MEMORY # CHECK-IMPORT-DEFAULT-NEXT: Memory: -# CHECK-IMPORT-DEFAULT-NEXT: Minimum: 0x2 +# CHECK-IMPORT-DEFAULT-NEXT: Minimum: 0x1 # CHECK-IMPORT-DEFAULT-NEXT: - Type: # RUN:wasm-ld --import-memory=foo,bar --export-memory=qux -o %t.both.wasm %t.start.o @@ -91,7 +91,7 @@ # CHECK-BOTH-NEXT: Field: bar # CHECK-BOTH-NEXT: Kind: MEMORY # CHECK-BOTH-NEXT: Memory: -# CHECK-BOTH-NEXT: Minimum: 0x2 +# CHECK-BOTH-NEXT: Minimum: 0x1 # CHECK-BOTH: - Type: EXPORT # CHECK-BOTH-NEXT: Exports: # CHECK-BOTH-NEXT: - Name: qux diff --git a/lld/test/wasm/merge-string.s b/lld/test/wasm/merge-string.s index a4b89abf..229f393 100644 --- a/lld/test/wasm/merge-string.s +++ b/lld/test/wasm/merge-string.s @@ -41,21 +41,21 @@ negative_addend: // COMMON-NEXT: Mutable: true // COMMON-NEXT: InitExpr: // COMMON-NEXT: Opcode: I32_CONST -// COMMON-NEXT: Value: 66576 +// COMMON-NEXT: Value: 65536 // COMMON-NEXT: - Index: 1 // COMMON-NEXT: Type: I32 // COMMON-NEXT: Mutable: false // COMMON-NEXT: InitExpr: // COMMON-NEXT: Opcode: I32_CONST -// MERGE-NEXT: Value: 1024 -// NOMERGE-NEXT: Value: 1028 +// MERGE-NEXT: Value: 65536 +// NOMERGE-NEXT: Value: 65540 // COMMON-NEXT: - Index: 2 // COMMON-NEXT: Type: I32 // COMMON-NEXT: Mutable: false // COMMON-NEXT: InitExpr: // COMMON-NEXT: Opcode: I32_CONST -// MERGE-NEXT: Value: 1025 -// NOMERGE-NEXT: Value: 1029 +// MERGE-NEXT: Value: 65537 +// NOMERGE-NEXT: Value: 65541 // COMMON-NEXT: - Type: EXPORT // COMMON-NEXT: Exports: // COMMON-NEXT: - Name: memory @@ -71,11 +71,11 @@ negative_addend: // // COMMON: - Type: DATA // COMMON-NEXT: Segments: -// COMMON-NEXT: - SectionOffset: 7 +// COMMON-NEXT: - SectionOffset: 8 // COMMON-NEXT: InitFlags: 0 // COMMON-NEXT: Offset: // COMMON-NEXT: Opcode: I32_CONST -// COMMON-NEXT: Value: 1024 +// COMMON-NEXT: Value: 65536 // MERGE-NEXT: Content: '61626300' // NOMERGE-NEXT: Content: '6162630061626300626300' diff --git a/lld/test/wasm/multi-table.s b/lld/test/wasm/multi-table.s index afe8dda..31cba9f 100644 --- a/lld/test/wasm/multi-table.s +++ b/lld/test/wasm/multi-table.s @@ -87,7 +87,7 @@ call_indirect_explicit_tables: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66576 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory @@ -127,14 +127,14 @@ call_indirect_explicit_tables: # CHECK-NEXT: Body: 42010B # CHECK-NEXT: - Index: 3 # CHECK-NEXT: Locals: [] -# CHECK-NEXT: Body: 41002802808880800011818080800083808080001A41002802848880800011828080800083808080001A0B +# CHECK-NEXT: Body: 41002802808084800011818080800083808080001A41002802848084800011828080800083808080001A0B # CHECK-NEXT: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: '0100000002000000' # CHECK-NEXT: - Type: CUSTOM # CHECK-NEXT: Name: name diff --git a/lld/test/wasm/no-strip-segment.s b/lld/test/wasm/no-strip-segment.s index e70acae..2b79ed6 100644 --- a/lld/test/wasm/no-strip-segment.s +++ b/lld/test/wasm/no-strip-segment.s @@ -47,16 +47,16 @@ grab_liba: # "greetings" section # CHECK: - Type: DATA # CHECK: Segments: -# CHECK: - SectionOffset: 7 +# CHECK: - SectionOffset: 8 # CHECK: InitFlags: 0 # CHECK: Offset: # CHECK: Opcode: I32_CONST -# CHECK: Value: 1024 +# CHECK: Value: 65536 # CHECK: Content: 68656C6C6F00776F726C6400 # "weahters" section. -# CHECK: - SectionOffset: 25 +# CHECK: - SectionOffset: 27 # CHECK: InitFlags: 0 # CHECK: Offset: # CHECK: Opcode: I32_CONST -# CHECK: Value: 1036 +# CHECK: Value: 65548 # CHECK: Content: 636C6F75647900 diff --git a/lld/test/wasm/no-tls.s b/lld/test/wasm/no-tls.s index c0786c8..c082c1e 100644 --- a/lld/test/wasm/no-tls.s +++ b/lld/test/wasm/no-tls.s @@ -28,7 +28,7 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # __tls_base # CHECK-NEXT: - Index: 1 diff --git a/lld/test/wasm/page-size.s b/lld/test/wasm/page-size.s index a2bf694..17850b5 100644 --- a/lld/test/wasm/page-size.s +++ b/lld/test/wasm/page-size.s @@ -19,7 +19,7 @@ foo: # CHECK-CUSTOM: - Type: MEMORY # CHECK-CUSTOM-NEXT: Memories: # CHECK-CUSTOM-NEXT: - Flags: [ HAS_PAGE_SIZE ] -# CHECK-CUSTOM-NEXT: Minimum: 0x10410 +# CHECK-CUSTOM-NEXT: Minimum: 0x10004 # CHECK-CUSTOM-NEXT: PageSize: 0x1 # RUN: llvm-objdump --disassemble-symbols=_start %t.custom.wasm | FileCheck %s --check-prefix=CHECK-CUSTOM-DIS @@ -51,7 +51,7 @@ foo: # CHECK-CUSTOM-IMPORT-NEXT: Kind: MEMORY # CHECK-CUSTOM-IMPORT-NEXT: Memory: # CHECK-CUSTOM-IMPORT-NEXT: Flags: [ HAS_PAGE_SIZE ] -# CHECK-CUSTOM-IMPORT-NEXT: Minimum: 0x10410 +# CHECK-CUSTOM-IMPORT-NEXT: Minimum: 0x10004 # CHECK-CUSTOM-IMPORT-NEXT: PageSize: 0x1 # RUN: llvm-objdump --disassemble-symbols=_start %t.custom-import.wasm | FileCheck %s --check-prefix=CHECK-CUSTOM-IMPORT-DIS diff --git a/lld/test/wasm/pic-static.ll b/lld/test/wasm/pic-static.ll index 794b721..12ac4c3 100644 --- a/lld/test/wasm/pic-static.ll +++ b/lld/test/wasm/pic-static.ll @@ -62,7 +62,7 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: Value: 65536 ; GOT.func.ret32 ; CHECK-NEXT: - Index: 1 @@ -70,7 +70,7 @@ entry: ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Value: 1 ; GOT.func.missing_function ; CHECK-NEXT: - Index: 2 @@ -102,7 +102,7 @@ entry: ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; GOT.mem.ret32_ptr ; CHECK-NEXT: - Index: 6 @@ -110,7 +110,7 @@ entry: ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1032 +; CHECK-NEXT: Value: 65544 ; __memory_base ; CHECK-NEXT: - Index: 7 diff --git a/lld/test/wasm/reloc-relative.s b/lld/test/wasm/reloc-relative.s index fde1d1d..5aab061 100644 --- a/lld/test/wasm/reloc-relative.s +++ b/lld/test/wasm/reloc-relative.s @@ -50,40 +50,40 @@ far: # CHECK: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: 68656C6C6F0A00 -# CHECK-NEXT: - SectionOffset: 20 +# CHECK-NEXT: - SectionOffset: 22 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1031 +# CHECK-NEXT: Value: 65543 # CHECK-NEXT: Content: 000000002A000000 -# CHECK-NEXT: - SectionOffset: 34 +# CHECK-NEXT: - SectionOffset: 37 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1039 +# CHECK-NEXT: Value: 65551 # CHECK-NEXT: Content: FCFFFFFFFCFFFFFF -# CHECK-NEXT: - SectionOffset: 48 +# CHECK-NEXT: - SectionOffset: 52 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1047 +# CHECK-NEXT: Value: 65559 # CHECK-NEXT: Content: E9FFFFFFE9FFFFFF -# CHECK-NEXT: - SectionOffset: 62 +# CHECK-NEXT: - SectionOffset: 67 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1055 +# CHECK-NEXT: Value: 65567 # CHECK-NEXT: Content: '0800000008000000' -# CHECK-NEXT: - SectionOffset: 76 +# CHECK-NEXT: - SectionOffset: 82 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1063 +# CHECK-NEXT: Value: 65575 # CHECK-NEXT: Content: '15000000' diff --git a/lld/test/wasm/runtime-relocations-himem.s b/lld/test/wasm/runtime-relocations-himem.s new file mode 100644 index 0000000..a12a93a --- /dev/null +++ b/lld/test/wasm/runtime-relocations-himem.s @@ -0,0 +1,60 @@ +## Verifies runtime relocation code for addresses over 2gb works correctly. +## We have had issues with LEB encoding of address over 2gb in i32.const +## instruction leading to invalid binaries. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --global-base=2147483648 --experimental-pic --unresolved-symbols=import-dynamic -no-gc-sections --shared-memory --no-entry -o %t.wasm %t.o +# XUN: obj2yaml %t.wasm | FileCheck %s +# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s -- + +.globl tls_sym +.globl data_sym +.globl _start +.globaltype __tls_base, i32 + +_start: + .functype _start () -> () + global.get __tls_base + i32.const tls_sym@TLSREL + i32.add + drop + i32.const data_sym + drop + end_function + +.section tls_sec,"T",@ +.p2align 2 +tls_sym: + .int32 0 + .int32 extern_sym + .size tls_sym, 8 + +.section data_sec,"",@ +.p2align 2 +data_sym: + .int32 0 + .int32 extern_sym + .size data_sym, 8 + +.section .custom_section.target_features,"",@ + .int8 2 + .int8 43 + .int8 7 + .ascii "atomics" + .int8 43 + .int8 11 + .ascii "bulk-memory" + +# CHECK: <__wasm_apply_data_relocs>: +# CHECK-EMPTY: +# CHECK-NEXT: i32.const -2147483636 +# CHECK-NEXT: global.get 0 +# CHECK-NEXT: i32.store 0 +# CHECK-NEXT: end + +# CHECK: <__wasm_apply_tls_relocs>: +# CHECK-EMPTY: +# CHECK-NEXT: i32.const -2147483644 +# CHECK-NEXT: global.get 0 +# CHECK-NEXT: i32.store 0 +# CHECK-NEXT: end diff --git a/lld/test/wasm/shared-memory-no-atomics.yaml b/lld/test/wasm/shared-memory-no-atomics.yaml index 942c690..62f4ac9 100644 --- a/lld/test/wasm/shared-memory-no-atomics.yaml +++ b/lld/test/wasm/shared-memory-no-atomics.yaml @@ -55,7 +55,7 @@ Sections: # NO-SHARED: - Type: MEMORY # NO-SHARED-NEXT: Memories: -# NO-SHARED-NEXT: - Minimum: 0x2 +# NO-SHARED-NEXT: - Minimum: 0x1 # NO-SHARED-NOT: Maximum: # SHARED: --shared-memory is disallowed by {{.*}}shared-memory-no-atomics.yaml.tmp1.o because it was not compiled with 'atomics' or 'bulk-memory' features. diff --git a/lld/test/wasm/shared-memory.yaml b/lld/test/wasm/shared-memory.yaml index 4cdbb95..b3490c8 100644 --- a/lld/test/wasm/shared-memory.yaml +++ b/lld/test/wasm/shared-memory.yaml @@ -1,16 +1,16 @@ # RUN: yaml2obj %s -o %t1.o -# RUN: wasm-ld --no-entry --shared-memory --features=atomics,bulk-memory %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED +# RUN: wasm-ld --no-entry --no-gc-sections --shared-memory --features=atomics,bulk-memory %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED -# RUN: not wasm-ld --no-entry --shared-memory --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED +# RUN: not wasm-ld --no-entry --no-gc-sections --shared-memory --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED -# RUN: not wasm-ld --no-entry --shared-memory --max-memory=131072 --features=bulk-memory %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-ATOMICS +# RUN: not wasm-ld --no-entry --no-gc-sections --shared-memory --max-memory=131072 --features=bulk-memory %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-ATOMICS -# RUN: not wasm-ld --no-entry --shared-memory --max-memory=131072 --features=atomics %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-BULK-MEM +# RUN: not wasm-ld --no-entry --no-gc-sections --shared-memory --max-memory=131072 --features=atomics %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-BULK-MEM # RUN: wasm-ld --relocatable --features=atomics %t1.o -o - | obj2yaml | FileCheck %s --check-prefix ATOMICS-RELOCATABLE -# RUN: wasm-ld --no-entry --shared-memory --max-memory=131072 --features=atomics,bulk-memory %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED +# XUN: wasm-ld --no-entry --no-gc-sections --shared-memory --max-memory=131072 --features=atomics,bulk-memory %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED --- !WASM FileHeader: @@ -22,7 +22,7 @@ Sections: Field: __linear_memory Kind: MEMORY Memory: - Minimum: 0x00000001 + Minimum: 0x00000009 - Module: env Field: __indirect_function_table Kind: TABLE diff --git a/lld/test/wasm/stack-first.test b/lld/test/wasm/stack-first.test index 72e1a00..91f06a4 100644 --- a/lld/test/wasm/stack-first.test +++ b/lld/test/wasm/stack-first.test @@ -5,9 +5,20 @@ ; Also test that __heap_base is still aligned with the --stack-first option. RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/stack-first.s -o %t.o -RUN: wasm-ld -z stack-size=512 --stack-first --export=__data_end --export=__heap_base --export=someByte -o %t.wasm %t.o + +; Check that the default is `--stack-first` +RUN: wasm-ld -z stack-size=512 --export=__data_end --export=__heap_base --export=someByte -o %t.wasm %t.o +RUN: obj2yaml %t.wasm | FileCheck %s + +; Check `--no-stack-first` +RUN: wasm-ld -z stack-size=512 --no-stack-first --export=__data_end --export=__heap_base --export=someByte -o %t.wasm %t.o +RUN: obj2yaml %t.wasm | FileCheck %s --check-prefix=NOT-FIRST + +; Check `--stack-first` +RUN: wasm-ld -z stack-size=512 --no-stack-first --stack-first --export=__data_end --export=__heap_base --export=someByte -o %t.wasm %t.o RUN: obj2yaml %t.wasm | FileCheck %s + CHECK: - Type: GLOBAL CHECK-NEXT: Globals: CHECK-NEXT: - Index: 0 @@ -51,3 +62,19 @@ CHECK-NEXT: Index: 2 CHECK-NEXT: - Name: __heap_base CHECK-NEXT: Kind: GLOBAL CHECK-NEXT: Index: 3 + +NOT-FIRST: - Type: GLOBAL +NOT-FIRST-NEXT: Globals: +NOT-FIRST-NEXT: - Index: 0 +NOT-FIRST-NEXT: Type: I32 +NOT-FIRST-NEXT: Mutable: true +NOT-FIRST-NEXT: InitExpr: +NOT-FIRST-NEXT: Opcode: I32_CONST +NOT-FIRST-NEXT: Value: 1552 +NOT-FIRST-NEXT: - Index: 1 +NOT-FIRST-NEXT: Type: I32 +NOT-FIRST-NEXT: Mutable: false +NOT-FIRST-NEXT: InitExpr: +NOT-FIRST-NEXT: Opcode: I32_CONST +NOT-FIRST-NEXT: Value: 1024 + diff --git a/lld/test/wasm/startstop.ll b/lld/test/wasm/startstop.ll index e7a5c80..c22956f 100644 --- a/lld/test/wasm/startstop.ll +++ b/lld/test/wasm/startstop.ll @@ -27,19 +27,19 @@ entry: ; CHECK: - Type: DATA ; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: - SectionOffset: 8 ; CHECK-NEXT: InitFlags: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: Content: 03000000040000002A0000002B000000 -; ASM: 0000006e <get_start>: +; ASM: 00000070 <get_start>: ; ASM-EMPTY: -; ASM-NEXT: 70: i32.const 1024 -; ASM-NEXT: 76: end +; ASM-NEXT: 72: i32.const 65536 +; ASM-NEXT: 78: end -; ASM: 00000077 <get_end>: +; ASM: 00000079 <get_end>: ; ASM-EMPTY: -; ASM-NEXT: 79: i32.const 1040 -; ASM-NEXT: 7f: end +; ASM-NEXT: 7b: i32.const 65552 +; ASM-NEXT: 81: end diff --git a/lld/test/wasm/table-base.s b/lld/test/wasm/table-base.s index 56fff41..92156c4 100644 --- a/lld/test/wasm/table-base.s +++ b/lld/test/wasm/table-base.s @@ -29,7 +29,7 @@ _start: # CHECK-DEFAULT-NEXT: Mutable: true # CHECK-DEFAULT-NEXT: InitExpr: # CHECK-DEFAULT-NEXT: Opcode: I32_CONST -# CHECK-DEFAULT-NEXT: Value: 66560 +# CHECK-DEFAULT-NEXT: Value: 65536 # CHECK-DEFAULT-NEXT: - Index: 1 # CHECK-DEFAULT-NEXT: Type: I32 # CHECK-DEFAULT-NEXT: Mutable: false @@ -58,7 +58,7 @@ _start: # CHECK-100-NEXT: Mutable: true # CHECK-100-NEXT: InitExpr: # CHECK-100-NEXT: Opcode: I32_CONST -# CHECK-100-NEXT: Value: 66560 +# CHECK-100-NEXT: Value: 65536 # CHECK-100-NEXT: - Index: 1 # CHECK-100-NEXT: Type: I32 # CHECK-100-NEXT: Mutable: false diff --git a/lld/test/wasm/tls-align.s b/lld/test/wasm/tls-align.s index 4fd296e..3b51165 100644 --- a/lld/test/wasm/tls-align.s +++ b/lld/test/wasm/tls-align.s @@ -65,7 +65,7 @@ tls2: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66592 +# CHECK-NEXT: Value: 65536 # __tls_base # CHECK-NEXT: - Index: 1 diff --git a/lld/test/wasm/tls-non-shared-memory-basic.s b/lld/test/wasm/tls-non-shared-memory-basic.s index 8ef0173..66ccf8f 100644 --- a/lld/test/wasm/tls-non-shared-memory-basic.s +++ b/lld/test/wasm/tls-non-shared-memory-basic.s @@ -27,11 +27,11 @@ tls1: # CHECK: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: 2B000000 # CHECK-NEXT: - Type: CUSTOM # CHECK-NOT: - Type: IMPORT diff --git a/lld/test/wasm/tls-non-shared-memory.s b/lld/test/wasm/tls-non-shared-memory.s index 04fbb62..0d73acb 100644 --- a/lld/test/wasm/tls-non-shared-memory.s +++ b/lld/test/wasm/tls-non-shared-memory.s @@ -63,38 +63,38 @@ tls1: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66576 +# CHECK-NEXT: Value: 65536 # __tls_base # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # GOT.data.internal.tls1 # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK: - Type: DATA # .data # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: 2B000000 # .tdata -# CHECK-NEXT: - SectionOffset: 17 +# CHECK-NEXT: - SectionOffset: 19 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1028 +# CHECK-NEXT: Value: 65540 # CHECK-NEXT: Content: 2A000000 # CHECK-NEXT: - Type: CUSTOM diff --git a/lld/test/wasm/tls.s b/lld/test/wasm/tls.s index b1f47f6..21f25f5 100644 --- a/lld/test/wasm/tls.s +++ b/lld/test/wasm/tls.s @@ -98,7 +98,7 @@ tls3: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66592 +# CHECK-NEXT: Value: 65536 # __tls_base # CHECK-NEXT: - Index: 1 diff --git a/lld/test/wasm/undefined-weak-call.s b/lld/test/wasm/undefined-weak-call.s index 7490104..47775c8 100644 --- a/lld/test/wasm/undefined-weak-call.s +++ b/lld/test/wasm/undefined-weak-call.s @@ -61,7 +61,7 @@ callWeakFuncs: # CHECK-NEXT: Maximum: 0x1 # CHECK-NEXT: - Type: MEMORY # CHECK-NEXT: Memories: -# CHECK-NEXT: - Minimum: 0x2 +# CHECK-NEXT: - Minimum: 0x1 # CHECK-NEXT: - Type: GLOBAL # CHECK-NEXT: Globals: # CHECK-NEXT: - Index: 0 @@ -69,7 +69,7 @@ callWeakFuncs: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/weak-alias-overide.ll b/lld/test/wasm/weak-alias-overide.ll index ca6f4bf..30bf7cf 100644 --- a/lld/test/wasm/weak-alias-overide.ll +++ b/lld/test/wasm/weak-alias-overide.ll @@ -44,7 +44,7 @@ entry: ; CHECK-NEXT: Maximum: 0x3 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: -; CHECK-NEXT: - Minimum: 0x2 +; CHECK-NEXT: - Minimum: 0x1 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: ; CHECK-NEXT: - Index: 0 @@ -52,7 +52,7 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/weak-alias.ll b/lld/test/wasm/weak-alias.ll index 1768b8f..86e42a7 100644 --- a/lld/test/wasm/weak-alias.ll +++ b/lld/test/wasm/weak-alias.ll @@ -41,7 +41,7 @@ entry: ; CHECK-NEXT: Maximum: 0x2 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: -; CHECK-NEXT: - Minimum: 0x2 +; CHECK-NEXT: - Minimum: 0x1 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: ; CHECK-NEXT: - Index: 0 @@ -49,7 +49,7 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: Value: 65536 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/weak-symbols.s b/lld/test/wasm/weak-symbols.s index 165ec17..ed85851 100644 --- a/lld/test/wasm/weak-symbols.s +++ b/lld/test/wasm/weak-symbols.s @@ -48,13 +48,13 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66576 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: false # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory @@ -97,11 +97,11 @@ _start: # CHECK-NEXT: Body: 4181808080000B # CHECK-NEXT: - Type: DATA # CHECK-NEXT: Segments: -# CHECK-NEXT: - SectionOffset: 7 +# CHECK-NEXT: - SectionOffset: 8 # CHECK-NEXT: InitFlags: 0 # CHECK-NEXT: Offset: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 1024 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: Content: '01000000' # CHECK-NEXT: - Type: CUSTOM # CHECK-NEXT: Name: name diff --git a/lld/test/wasm/weak-undefined-pic.s b/lld/test/wasm/weak-undefined-pic.s index 5937380..1a3a171 100644 --- a/lld/test/wasm/weak-undefined-pic.s +++ b/lld/test/wasm/weak-undefined-pic.s @@ -45,7 +45,7 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # Global 'undefined_weak:foo' representing the GOT entry for foo # Unlike other internal GOT entries that need to be mutable this one # is immutable and not updated by `__wasm_apply_global_relocs` diff --git a/lld/test/wasm/weak-undefined.s b/lld/test/wasm/weak-undefined.s index e1f551d..558cac5 100644 --- a/lld/test/wasm/weak-undefined.s +++ b/lld/test/wasm/weak-undefined.s @@ -67,7 +67,7 @@ _start: # CHECK-NEXT: Maximum: 0x1 # CHECK-NEXT: - Type: MEMORY # CHECK-NEXT: Memories: -# CHECK-NEXT: - Minimum: 0x2 +# CHECK-NEXT: - Minimum: 0x1 # CHECK-NEXT: - Type: GLOBAL # CHECK-NEXT: Globals: # CHECK-NEXT: - Index: 0 @@ -75,7 +75,7 @@ _start: # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST -# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: Value: 65536 # CHECK-NEXT: - Type: EXPORT # CHECK-NEXT: Exports: # CHECK-NEXT: - Name: memory diff --git a/lld/test/wasm/wrap_import.s b/lld/test/wasm/wrap_import.s new file mode 100644 index 0000000..ce3b6f5 --- /dev/null +++ b/lld/test/wasm/wrap_import.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o +# RUN: wasm-ld -wrap nosuchsym -wrap foo -allow-undefined -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s + +.globl foo +.globl _start + +foo: + .functype foo () -> () + end_function + +_start: + .functype _start () -> () + call foo + end_function + +# CHECK: - Type: IMPORT +# CHECK-NEXT: Imports: +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __wrap_foo +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT SigIndex: 0 + +# CHECK: - Type: CODE +# CHECK-NEXT: Functions: +# CHECK-NEXT: Index: 1 + +# CHECK: FunctionNames: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Name: __wrap_foo +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: Name: _start diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 9c0e1b5..97e5078 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -595,7 +595,7 @@ static void readConfigs(opt::InputArgList &args) { ctx.arg.shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck); ctx.arg.stripAll = args.hasArg(OPT_strip_all); ctx.arg.stripDebug = args.hasArg(OPT_strip_debug); - ctx.arg.stackFirst = args.hasArg(OPT_stack_first); + ctx.arg.stackFirst = args.hasFlag(OPT_stack_first, OPT_no_stack_first, true); ctx.arg.trace = args.hasArg(OPT_trace); ctx.arg.thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); ctx.arg.thinLTOCachePolicy = CHECK( @@ -1173,9 +1173,10 @@ struct WrappedSymbol { Symbol *wrap; }; -static Symbol *addUndefined(StringRef name) { +static Symbol *addUndefined(StringRef name, + const WasmSignature *signature = nullptr) { return symtab->addUndefinedFunction(name, std::nullopt, std::nullopt, - WASM_SYMBOL_UNDEFINED, nullptr, nullptr, + WASM_SYMBOL_UNDEFINED, nullptr, signature, false); } @@ -1198,7 +1199,8 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { continue; Symbol *real = addUndefined(saver().save("__real_" + name)); - Symbol *wrap = addUndefined(saver().save("__wrap_" + name)); + Symbol *wrap = + addUndefined(saver().save("__wrap_" + name), sym->getSignature()); v.push_back({sym, real, wrap}); // We want to tell LTO not to inline symbols to be overwritten diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp index 44927e7a..14e02e6 100644 --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -423,8 +423,6 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { bool is64 = ctx.arg.is64.value_or(false); bool generated = false; - unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST - : WASM_OPCODE_I32_CONST; unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; @@ -451,8 +449,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { << " output offset=" << offset << "\n"); // Calculate the address at which to apply the relocation - writeU8(os, opcode_ptr_const, "CONST"); - writeSleb128(os, offset, "offset"); + writePtrConst(os, offset, is64, "offset"); // In PIC mode we need to add the __memory_base if (ctx.isPic) { @@ -466,8 +463,6 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { // Now figure out what we want to store at this location bool is64 = relocIs64(rel.Type); - unsigned opcode_reloc_const = - is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST; unsigned opcode_reloc_add = is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; unsigned opcode_reloc_store = @@ -477,8 +472,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, sym->getGOTIndex(), "global index"); if (rel.Addend) { - writeU8(os, opcode_reloc_const, "CONST"); - writeSleb128(os, rel.Addend, "addend"); + writePtrConst(os, rel.Addend, is64, "addend"); writeU8(os, opcode_reloc_add, "ADD"); } } else { @@ -491,8 +485,8 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { baseSymbol = ctx.sym.tlsBase; writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, baseSymbol->getGlobalIndex(), "base"); - writeU8(os, opcode_reloc_const, "CONST"); - writeSleb128(os, file->calcNewValue(rel, tombstone, this), "offset"); + writePtrConst(os, file->calcNewValue(rel, tombstone, this), is64, + "offset"); writeU8(os, opcode_reloc_add, "ADD"); } diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 2f699e2..33ecf03 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -250,8 +250,9 @@ def no_entry: FF<"no-entry">, def no_shlib_sigcheck: FF<"no-shlib-sigcheck">, HelpText<"Do not check signatures of functions defined in shared libraries.">; -def stack_first: FF<"stack-first">, - HelpText<"Place stack at start of linear memory rather than after data">; +defm stack_first: B<"stack-first", + "Place stack at start of linear memory (default)", + "Place the stack after static data region">; def table_base: JJ<"table-base=">, HelpText<"Table offset at which to place address taken functions (Defaults to 1)">; diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index e119270..5e7b9c2 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -196,7 +196,9 @@ void ImportSection::addImport(Symbol *sym) { StringRef module = sym->importModule.value_or(defaultModule); StringRef name = sym->importName.value_or(sym->getName()); if (auto *f = dyn_cast<FunctionSymbol>(sym)) { - ImportKey<WasmSignature> key(*(f->getSignature()), module, name); + const WasmSignature *sig = f->getSignature(); + assert(sig && "imported functions must have a signature"); + ImportKey<WasmSignature> key(*sig, module, name); auto entry = importedFunctions.try_emplace(key, numImportedFunctions); if (entry.second) { importedSymbols.emplace_back(sym); @@ -434,8 +436,6 @@ void GlobalSection::addInternalGOTEntry(Symbol *sym) { void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { assert(!ctx.arg.extendedConst); bool is64 = ctx.arg.is64.value_or(false); - unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST - : WASM_OPCODE_I32_CONST; unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; @@ -452,8 +452,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base"); // Add the virtual address of the data symbol - writeU8(os, opcode_ptr_const, "CONST"); - writeSleb128(os, d->getVA(), "offset"); + writePtrConst(os, d->getVA(), is64, "offset"); } else if (auto *f = dyn_cast<FunctionSymbol>(sym)) { if (f->isStub) continue; @@ -462,8 +461,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { writeUleb128(os, ctx.sym.tableBase->getGlobalIndex(), "__table_base"); // Add the table index to __table_base - writeU8(os, opcode_ptr_const, "CONST"); - writeSleb128(os, f->getTableIndex(), "offset"); + writePtrConst(os, f->getTableIndex(), is64, "offset"); } else { assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); continue; |
