Skip to content

Commit 69c8d08

Browse files
committed
Put large common blocks into .lbss for the medium and large code models
For the medium and large code models on x86-64, the bss is split into two parts, .bss for regular sized data, and .lbss for data larger than that specified by -large-data-threshold (for the medium code model). This change tries to mimick what gcc does for the medium and large code models for Fortran COMMON blocks: program test implicit integer (i-n) implicit real*8 (a-h, o-z) parameter (n1=77777, n2=77777) common v2(n1,n2) common /ccc/ v6 v6 = 1 v2(6777,6777) = 2 write (*,*) v6, v2(6777, 6777) end program test Currently, we generate: 0000000000000008 O *COM* 0000000000000008 ccc_ 0000000b44834508 O *COM* 0000000000000008 __BLNK and ld and lld both fail to link with -mcmodel=medium. /usr/bin/ld: failed to convert GOTPCREL relocation; relink with --no-relax or ld.lld: error: /usr/lib/gcc/x86_64-redhat-linux/11/crtbeginS.o:(.text+0x76): relocation R_X86_64_PC32 out of range: 48394103061 is not in [-2147483648, 2147483647]; references section '.bss' With this change, __BLNK is marked as LARGE_COMMON (SHN_AMD64_LCOMMON), and ends up in .lbss. *.o: Sections: ... 1 .lbss 00000000 0000000000000000 0000000000000000 000000fb 2**0 ALLOC ... SYMBOL TABLE: 0000000000000008 O *COM* 0000000000000008 ccc_ 0000000b44834508 O LARGE_COMMON 0000000000000008 __BLNK__ a.out: Sections: ... 25 .bss 00000009 0000000000003cf0 0000000000003cf0 00000cf0 2**3 ALLOC 26 .lbss b44834508 0000000000003d00 0000000000003d00 00000cf0 2**3 ALLOC SYMBOL TABLE: 0000000000003cf0 g O .bss 0000000000000008 ccc_ 0000000000003d00 g O .lbss 0000000b44834508 __BLNK__ In the assembly, this will appear as: .section .lbss,"awl",@nobits .type __BLNK__,@object .largecomm __BLNK__,48394093832,8 .type ccc_,@object .comm ccc_,8,8 For the large code model, all common blocks will end up in lbss. Previously, the above example wouldn't link statically with GNU ld. The change also includes support for parsing the largecomm directive. There will be a PR for the chages to lld to handle the SHN_AMD64_LCOMMON section.
1 parent 9ce0dae commit 69c8d08

File tree

16 files changed

+208
-6
lines changed

16 files changed

+208
-6
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,11 @@ enum {
589589
SHN_MIPS_SUNDEFINED = 0xff04 // Undefined symbols for global data area
590590
};
591591

592+
// x86-64 speciifc section index
593+
enum {
594+
SHN_AMD64_LCOMMON = 0xff02, // Large FORTRAN COMMON variables
595+
};
596+
592597
// ELF Relocation types for Mips
593598
enum {
594599
#include "ELFRelocs/Mips.def"

llvm/include/llvm/MC/MCELFStreamer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class MCELFStreamer : public MCObjectStreamer {
5656
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
5757
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
5858
Align ByteAlignment) override;
59+
void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
60+
Align ByteAlignment) override;
5961

6062
void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
6163
void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,14 @@ class LLVM_ABI MCStreamer {
677677
virtual void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
678678
Align ByteAlignment) = 0;
679679

680+
/// Emit a large common (.largecomm) symbol.
681+
///
682+
/// \param Symbol - The common symbol to emit.
683+
/// \param Size - The size of the common symbol.
684+
/// \param ByteAlignment - The alignment of the common symbol in bytes.
685+
virtual void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
686+
Align ByteAlignment);
687+
680688
/// Emit a local common (.lcomm) symbol.
681689
///
682690
/// \param Symbol - The common symbol to emit.

llvm/include/llvm/MC/MCSymbolELF.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class MCSymbolELF : public MCSymbol {
1717
/// An expression describing how to calculate the size of a symbol. If a
1818
/// symbol has no size this field will be NULL.
1919
const MCExpr *SymbolSize = nullptr;
20+
bool IsLargeCommon = false;
2021

2122
public:
2223
MCSymbolELF(const MCSymbolTableEntry *Name, bool isTemporary)
@@ -48,6 +49,9 @@ class MCSymbolELF : public MCSymbol {
4849
void setMemtag(bool Tagged);
4950
bool isMemtag() const;
5051

52+
bool isLargeCommon() const { return IsLargeCommon; }
53+
void setIsLargeCommon(bool V) { IsLargeCommon = V; }
54+
5155
private:
5256
void setIsBindingSet() const;
5357
};

llvm/include/llvm/Object/ELFTypes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
252252
return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON;
253253
}
254254

255+
bool isLargeCommon() const { return st_shndx == ELF::SHN_AMD64_LCOMMON; }
256+
255257
bool isDefined() const { return !isUndefined(); }
256258

257259
bool isProcessorSpecific() const {

llvm/include/llvm/Target/TargetLoweringObjectFile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
305305
return nullptr;
306306
}
307307

308+
virtual MCSection *LargeSectionForCommon(const GlobalObject *GO,
309+
SectionKind Kind,
310+
const TargetMachine &TM) const {
311+
return nullptr;
312+
}
313+
308314
protected:
309315
virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
310316
SectionKind Kind,

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -782,11 +782,18 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
782782
OutContext.reportError(SMLoc(), "symbol '" + Twine(GVSym->getName()) +
783783
"' is already defined");
784784

785+
SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);
786+
787+
// Place the large common variables in the .lbss section for the medium and
788+
// large code models on x86_64. (AMD64 ABI, 9.2.5 COMMON blocks)
789+
MCSection *largeCommonSec =
790+
getObjFileLowering().LargeSectionForCommon(GV, GVKind, TM);
791+
if (largeCommonSec)
792+
OutStreamer->switchSection(largeCommonSec);
793+
785794
if (MAI->hasDotTypeDotSizeDirective())
786795
OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_ELF_TypeObject);
787796

788-
SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);
789-
790797
const DataLayout &DL = GV->getDataLayout();
791798
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
792799

@@ -802,10 +809,12 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
802809
if (GVKind.isCommon()) {
803810
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
804811
// .comm _foo, 42, 4
805-
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
812+
if (largeCommonSec)
813+
OutStreamer->emitLargeCommonSymbol(GVSym, Size, Alignment);
814+
else
815+
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
806816
return;
807817
}
808-
809818
// Determine to which section this global should be emitted.
810819
MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, TM);
811820

llvm/lib/MC/ELFObjectWriter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/MC/MCELFObjectWriter.h"
2828
#include "llvm/MC/MCExpr.h"
2929
#include "llvm/MC/MCFixup.h"
30+
#include "llvm/MC/MCObjectFileInfo.h"
3031
#include "llvm/MC/MCObjectWriter.h"
3132
#include "llvm/MC/MCSection.h"
3233
#include "llvm/MC/MCSectionELF.h"
@@ -544,7 +545,10 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
544545
auto Shndx = Symbol.getIndex();
545546
if (!Shndx) {
546547
assert(!Local);
547-
Shndx = ELF::SHN_COMMON;
548+
if (Symbol.isLargeCommon())
549+
Shndx = ELF::SHN_AMD64_LCOMMON;
550+
else
551+
Shndx = ELF::SHN_COMMON;
548552
}
549553
MSD.SectionIndex = Shndx;
550554
} else if (Symbol.isUndefined()) {

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ class MCAsmStreamer final : public MCStreamer {
228228
void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
229229
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
230230
Align ByteAlignment) override;
231-
231+
void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
232+
Align ByteAlignment) override;
232233
/// Emit a local common (.lcomm) symbol.
233234
///
234235
/// @param Symbol - The common symbol to emit.
@@ -1075,6 +1076,19 @@ void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
10751076
}
10761077
}
10771078

1079+
void MCAsmStreamer::emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
1080+
Align ByteAlignment) {
1081+
OS << "\t.largecomm\t";
1082+
Symbol->print(OS, MAI);
1083+
OS << ',' << Size;
1084+
1085+
if (MAI->getCOMMDirectiveAlignmentIsInBytes())
1086+
OS << ',' << ByteAlignment.value();
1087+
else
1088+
OS << ',' << Log2(ByteAlignment);
1089+
EmitEOL();
1090+
}
1091+
10781092
void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
10791093
Align ByteAlign) {
10801094
OS << "\t.lcomm\t";

llvm/lib/MC/MCELFStreamer.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,23 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
244244
return true;
245245
}
246246

247+
void MCELFStreamer::emitLargeCommonSymbol(MCSymbol *S, uint64_t Size,
248+
Align ByteAlignment) {
249+
auto *Symbol = static_cast<MCSymbolELF *>(S);
250+
getAssembler().registerSymbol(*Symbol);
251+
252+
if (!Symbol->isBindingSet())
253+
Symbol->setBinding(ELF::STB_GLOBAL);
254+
255+
Symbol->setType(ELF::STT_OBJECT);
256+
257+
if (Symbol->declareCommon(Size, ByteAlignment))
258+
report_fatal_error(Twine("Symbol: ") + Symbol->getName() +
259+
" redeclared as different type");
260+
Symbol->setIsLargeCommon(true);
261+
Symbol->setSize(MCConstantExpr::create(Size, getContext()));
262+
}
263+
247264
void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
248265
Align ByteAlignment) {
249266
auto *Symbol = static_cast<MCSymbolELF *>(S);

0 commit comments

Comments
 (0)