diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 1beab8d33f4ba..013c8ae6f7ddd 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2530,7 +2530,10 @@ static void replaceCommonSymbols(Ctx &ctx) { if (!s) continue; - auto *bss = make(ctx, "COMMON", s->size, s->alignment); + auto *bss = + (s->isLargeCommon) + ? make(ctx, "LARGE_COMMON", s->size, s->alignment) + : make(ctx, "COMMON", s->size, s->alignment); bss->file = s->file; ctx.inputSections.push_back(bss); Defined(ctx, s->file, StringRef(), s->binding, s->stOther, s->type, diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index a5921feb18299..413f3a600174f 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1223,13 +1223,17 @@ void ObjFile::initializeSymbols(const object::ELFFile &obj) { Symbol *sym = symbols[i]; sym->isUsedInRegularObj = true; - if (LLVM_UNLIKELY(eSym.st_shndx == SHN_COMMON)) { + + bool isLargeCommon = LLVM_UNLIKELY(eSym.st_shndx == SHN_AMD64_LCOMMON) && + ctx.arg.emachine == EM_X86_64; + if (LLVM_UNLIKELY(eSym.st_shndx == SHN_COMMON) || isLargeCommon) { + if (value == 0 || value >= UINT32_MAX) Err(ctx) << this << ": common symbol '" << sym->getName() << "' has invalid alignment: " << value; hasCommonSyms = true; sym->resolve(ctx, CommonSymbol{ctx, this, StringRef(), binding, stOther, - type, value, size}); + type, value, size, isLargeCommon}); continue; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index ff7ef2dce5c79..8dc4241bc6bde 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -59,7 +59,7 @@ InputSectionBase::InputSectionBase(InputFile *file, StringRef name, Kind sectionKind) : SectionBase(sectionKind, file, name, type, flags, link, info, addralign, entsize), - bss(0), decodedCrel(0), keepUnique(0), nopFiller(0), + bss(0), lbss(0), decodedCrel(0), keepUnique(0), nopFiller(0), content_(data.data()), size(data.size()) { // In order to reduce memory allocation, we assume that mergeable // sections are smaller than 4 GiB, which is not an unreasonable diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index dc29fedbc5c53..74d6f4db5c1bc 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -168,6 +168,7 @@ class InputSectionBase : public SectionBase { LLVM_PREFERRED_TYPE(bool) uint8_t bss : 1; + uint8_t lbss : 1; // Whether this section is SHT_CREL and has been decoded to RELA by // relsOrRelas. diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 218c9d3a86184..0fbda4396dd88 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -70,9 +70,13 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const { return s->name; // A BssSection created for a common symbol is identified as "COMMON" in - // linker scripts. It should go to .bss section. + // linker scripts. It should go to .bss section. A large bss section, + // LbssCommon, created for a large common symbol is identified as + // "LARGE_COMMON". if (s->name == "COMMON") return ".bss"; + else if (s->name == "LARGE_COMMON") + return ".lbss"; if (hasSectionsCommand) return s->name; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c117e3b716c1b..6cec6d40b6c91 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -408,21 +408,23 @@ class Defined : public Symbol { class CommonSymbol : public Symbol { public: CommonSymbol(Ctx &ctx, InputFile *file, StringRef name, uint8_t binding, - uint8_t stOther, uint8_t type, uint64_t alignment, uint64_t size) + uint8_t stOther, uint8_t type, uint64_t alignment, uint64_t size, + bool isLargeCommon = false) : Symbol(CommonKind, file, name, binding, stOther, type), - alignment(alignment), size(size) { - } + alignment(alignment), size(size), isLargeCommon(isLargeCommon) {} void overwrite(Symbol &sym) const { Symbol::overwrite(sym, CommonKind); auto &s = static_cast(sym); s.alignment = alignment; s.size = size; + s.isLargeCommon = isLargeCommon; } static bool classof(const Symbol *s) { return s->isCommon(); } uint32_t alignment; uint64_t size; + bool isLargeCommon; }; class Undefined : public Symbol { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index bbf4b29a9fda5..0a3394cf9880c 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -397,6 +397,12 @@ BssSection::BssSection(Ctx &ctx, StringRef name, uint64_t size, this->size = size; } +LbssSection::LbssSection(Ctx &ctx, StringRef name, uint64_t size, + uint32_t alignment) + : BssSection(ctx, name, size, alignment) { + this->lbss = true; +} + EhFrameSection::EhFrameSection(Ctx &ctx) : SyntheticSection(ctx, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, 1) {} diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index ac3ec63f0a7a5..b7d8f86be4a0a 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -172,7 +172,7 @@ class BuildIdSection : public SyntheticSection { // We create three instances of this class for .bss, .bss.rel.ro and "COMMON", // that are used for writable symbols, read-only symbols and common symbols, // respectively. -class BssSection final : public SyntheticSection { +class BssSection : public SyntheticSection { public: BssSection(Ctx &, StringRef name, uint64_t size, uint32_t addralign); void writeTo(uint8_t *) override {} @@ -185,6 +185,17 @@ class BssSection final : public SyntheticSection { uint64_t size; }; +// LbssSection is used to reserve space for large common symbols on x86-64, +// "LARGE_COMMON". +class LbssSection final : public BssSection { +public: + LbssSection(Ctx &, StringRef name, uint64_t size, uint32_t addralign); + + static bool classof(const SectionBase *s) { + return isa(s) && cast(s)->lbss; + } +}; + class MipsGotSection final : public SyntheticSection { public: MipsGotSection(Ctx &); diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index e619b186dfe3d..ca6ec30e1f95e 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -589,6 +589,11 @@ enum { SHN_MIPS_SUNDEFINED = 0xff04 // Undefined symbols for global data area }; +// x86-64 speciifc section index +enum { + SHN_AMD64_LCOMMON = 0xff02, // Large FORTRAN COMMON variables +}; + // ELF Relocation types for Mips enum { #include "ELFRelocs/Mips.def"