Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/BinaryFormat/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCELFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class MCELFStreamer : public MCObjectStreamer {
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;
void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,14 @@ class LLVM_ABI MCStreamer {
virtual void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) = 0;

/// Emit a large common (.largecomm) symbol.
///
/// \param Symbol - The common symbol to emit.
/// \param Size - The size of the common symbol.
/// \param ByteAlignment - The alignment of the common symbol in bytes.
virtual void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment);

/// Emit a local common (.lcomm) symbol.
///
/// \param Symbol - The common symbol to emit.
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCSymbolELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class MCSymbolELF : public MCSymbol {
/// An expression describing how to calculate the size of a symbol. If a
/// symbol has no size this field will be NULL.
const MCExpr *SymbolSize = nullptr;
bool IsLargeCommon = false;

public:
MCSymbolELF(const MCSymbolTableEntry *Name, bool isTemporary)
Expand Down Expand Up @@ -48,6 +49,9 @@ class MCSymbolELF : public MCSymbol {
void setMemtag(bool Tagged);
bool isMemtag() const;

bool isLargeCommon() const { return IsLargeCommon; }
void setIsLargeCommon(bool V) { IsLargeCommon = V; }

private:
void setIsBindingSet() const;
};
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Object/ELFTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON;
}

bool isLargeCommon() const { return st_shndx == ELF::SHN_AMD64_LCOMMON; }

bool isDefined() const { return !isUndefined(); }

bool isProcessorSpecific() const {
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/TargetLoweringObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
return nullptr;
}

virtual MCSection *LargeSectionForCommon(const GlobalObject *GO,
SectionKind Kind,
const TargetMachine &TM) const {
return nullptr;
}

protected:
virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
SectionKind Kind,
Expand Down
17 changes: 13 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,11 +782,18 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
OutContext.reportError(SMLoc(), "symbol '" + Twine(GVSym->getName()) +
"' is already defined");

SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);

// Place the large common variables in the .lbss section for the medium and
// large code models on x86_64. (AMD64 ABI, 9.2.5 COMMON blocks)
MCSection *LargeCommonSec =
getObjFileLowering().LargeSectionForCommon(GV, GVKind, TM);
if (LargeCommonSec)
OutStreamer->switchSection(LargeCommonSec);

if (MAI->hasDotTypeDotSizeDirective())
OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_ELF_TypeObject);

SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);

const DataLayout &DL = GV->getDataLayout();
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());

Expand All @@ -802,10 +809,12 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
if (GVKind.isCommon()) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
// .comm _foo, 42, 4
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
if (LargeCommonSec)
OutStreamer->emitLargeCommonSymbol(GVSym, Size, Alignment);
else
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
return;
}

// Determine to which section this global should be emitted.
MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, TM);

Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/MC/ELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
Expand Down Expand Up @@ -544,7 +545,10 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
auto Shndx = Symbol.getIndex();
if (!Shndx) {
assert(!Local);
Shndx = ELF::SHN_COMMON;
if (Symbol.isLargeCommon())
Shndx = ELF::SHN_AMD64_LCOMMON;
else
Shndx = ELF::SHN_COMMON;
}
MSD.SectionIndex = Shndx;
} else if (Symbol.isUndefined()) {
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ class MCAsmStreamer final : public MCStreamer {
void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;
/// Emit a local common (.lcomm) symbol.
///
/// @param Symbol - The common symbol to emit.
Expand Down Expand Up @@ -1075,6 +1076,19 @@ void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
}
}

void MCAsmStreamer::emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {
OS << "\t.largecomm\t";
Symbol->print(OS, MAI);
OS << ',' << Size;

if (MAI->getCOMMDirectiveAlignmentIsInBytes())
OS << ',' << ByteAlignment.value();
else
OS << ',' << Log2(ByteAlignment);
EmitEOL();
}

void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlign) {
OS << "\t.lcomm\t";
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/MC/MCELFStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,23 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
return true;
}

void MCELFStreamer::emitLargeCommonSymbol(MCSymbol *S, uint64_t Size,
Align ByteAlignment) {
auto *Symbol = static_cast<MCSymbolELF *>(S);
getAssembler().registerSymbol(*Symbol);

if (!Symbol->isBindingSet())
Symbol->setBinding(ELF::STB_GLOBAL);

Symbol->setType(ELF::STT_OBJECT);

if (Symbol->declareCommon(Size, ByteAlignment))
report_fatal_error(Twine("Symbol: ") + Symbol->getName() +
" redeclared as different type");
Symbol->setIsLargeCommon(true);
Symbol->setSize(MCConstantExpr::create(Size, getContext()));
}

void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
Align ByteAlignment) {
auto *Symbol = static_cast<MCSymbolELF *>(S);
Expand Down
50 changes: 50 additions & 0 deletions llvm/lib/MC/MCParser/ELFAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class ELFAsmParser : public MCAsmParserExtension {
&ELFAsmParser::parseDirectiveSymbolAttribute>(".hidden");
addDirectiveHandler<&ELFAsmParser::parseDirectiveSubsection>(".subsection");
addDirectiveHandler<&ELFAsmParser::parseDirectiveCGProfile>(".cg_profile");
addDirectiveHandler<&ELFAsmParser::parseDirectiveLargecomm>(".largecomm");
}

// FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
Expand Down Expand Up @@ -126,6 +127,7 @@ class ELFAsmParser : public MCAsmParserExtension {
bool parseDirectiveSymbolAttribute(StringRef, SMLoc);
bool parseDirectiveSubsection(StringRef, SMLoc);
bool parseDirectiveCGProfile(StringRef, SMLoc);
bool parseDirectiveLargecomm(StringRef, SMLoc);

private:
bool parseSectionName(StringRef &SectionName);
Expand Down Expand Up @@ -886,6 +888,54 @@ bool ELFAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) {
return MCAsmParserExtension::parseDirectiveCGProfile(S, Loc);
}

bool ELFAsmParser::parseDirectiveLargecomm(StringRef, SMLoc Loc) {
if (getParser().checkForValidSection())
return true;

MCSymbol *Sym;
if (getParser().parseSymbol(Sym))
return TokError("expected identifier in directive");

if (getLexer().isNot(AsmToken::Comma))
return TokError("expected a comma");
Lex();

int64_t Size;
SMLoc SizeLoc = getLexer().getLoc();
if (getParser().parseAbsoluteExpression(Size))
return true;

int64_t Pow2Alignment = 0;
SMLoc Pow2AlignmentLoc;
if (getLexer().is(AsmToken::Comma)) {
Lex();
Pow2AlignmentLoc = getLexer().getLoc();
if (getParser().parseAbsoluteExpression(Pow2Alignment))
return true;

// If this target takes alignments in bytes (not log) validate and convert.
if (getLexer().getMAI().getCOMMDirectiveAlignmentIsInBytes()) {
if (!isPowerOf2_64(Pow2Alignment))
return Error(Pow2AlignmentLoc, "alignment must be a power of 2");
Pow2Alignment = Log2_64(Pow2Alignment);
}
}

if (parseEOL())
return true;

if (Size < 0)
return Error(SizeLoc, "size must be non-negative");

Sym->redefineIfPossible();
if (!Sym->isUndefined())
return Error(Loc, "invalid symbol redefinition");

getStreamer().emitLargeCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));

return false;
}

namespace llvm {

MCAsmParserExtension *createELFAsmParser() {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,8 @@ void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
StringRef Name, bool KeepOriginalSym) {}
void MCStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {}
void MCStreamer::emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {}
void MCStreamer::emitZerofill(MCSection *, MCSymbol *, uint64_t, Align, SMLoc) {
}
void MCStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/X86/X86TargetObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

#include "X86TargetObjectFile.h"
#include "MCTargetDesc/X86MCAsmInfo.h"
#include "X86TargetMachine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Target/TargetMachine.h"

Expand Down Expand Up @@ -71,3 +74,13 @@ const MCExpr *X86_64ELFTargetObjectFile::getIndirectSymViaGOTPCRel(
const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext());
return MCBinaryExpr::createAdd(Res, Off, getContext());
}

MCSection *X86_64ELFTargetObjectFile::LargeSectionForCommon(
const GlobalObject *GV, SectionKind Kind, const TargetMachine &TM) const {
auto &X86_TM = static_cast<const X86TargetMachine &>(TM);
if (GV && Kind.isCommon() && TM.isLargeGlobalValue(GV) && !X86_TM.isJIT()) {
unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_X86_64_LARGE;
return getContext().getELFSection(".lbss", ELF::SHT_NOBITS, Flags);
}
return nullptr;
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/X86TargetObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ namespace llvm {
const MCValue &MV, int64_t Offset,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const override;

MCSection *LargeSectionForCommon(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
};

} // end namespace llvm
Expand Down
58 changes: 58 additions & 0 deletions llvm/test/MC/X86/largecomm.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; RUN: llc -filetype=asm -code-model=medium %s --large-data-threshold=65636 -o - | FileCheck %s --check-prefix=CHECKASM-MEDIUM
; RUN: llc -filetype=asm -code-model=large %s -o - | FileCheck %s --check-prefix=CHECKASM-LARGE
; RUN: llc -filetype=asm -code-model=medium %s --large-data-threshold=65636 -o - | llvm-mc -triple x86_64-linux-gnu -filetype=obj - | llvm-readelf -s - | FileCheck %s --check-prefix=CHECKOBJ-MEDIUM
; RUN: llc -filetype=asm -code-model=large %s -o - | llvm-mc -triple x86_64-linux-gnu -filetype=obj - | llvm-readelf -s - | FileCheck %s --check-prefix=CHECKOBJ-LARGE

; CHECKASM-MEDIUM: .section .lbss,"awl",@nobits
; CHECKASM-MEDIUM-NEXT: .type __BLNK__,@object # @__BLNK__
; CHECKASM-MEDIUM-NEXT: .largecomm __BLNK__,48394093832,8
; CHECKASM-MEDIUM-NEXT: .type ccc_,@object # @ccc_
; CHECKASM-MEDIUM-NEXT: .comm ccc_,8,8

; CHECKASM-LARGE: .section .lbss,"awl",@nobits
; CHECKASM-LARGE-NEXT: .type __BLNK__,@object # @__BLNK__
; CHECKASM-LARGE-NEXT: .largecomm __BLNK__,48394093832,8
; CHECKASM-LARGE-NEXT: .type ccc_,@object # @ccc_
; CHECKASM-LARGE-NEXT: .largecomm ccc_,8,8

; CHECKOBJ-MEDIUM: 8 OBJECT GLOBAL DEFAULT COM ccc_
; CHECKOBJ-MEDIUM: 48394093832 OBJECT GLOBAL DEFAULT LARGE_COMMON __BLNK

; CHECKOBJ-LARGE: 8 OBJECT GLOBAL DEFAULT LARGE_COMMON ccc_
; CHECKOBJ-LARGE: 48394093832 OBJECT GLOBAL DEFAULT LARGE_COMMON __BLNK__

source_filename = "FIRModule"
target triple = "x86_64-unknown-linux-gnu"

@__BLNK__ = common global [48394093832 x i8] zeroinitializer, align 8
@ccc_ = common global [8 x i8] zeroinitializer, align 8
@_QFECn1 = internal constant i32 77777
@_QFECn2 = internal constant i32 77777

define void @_QQmain() #0 {
store double 1.000000e+00, ptr @ccc_, align 8
store double 2.000000e+00, ptr getelementptr inbounds nuw (i8, ptr @__BLNK__, i64 61600176), align 8
ret void
}

declare void @_FortranAProgramStart(i32, ptr, ptr, ptr) #1

declare void @_FortranAProgramEndStatement() #1

define i32 @main(i32 %0, ptr %1, ptr %2) #0 {
call void @_FortranAProgramStart(i32 %0, ptr %1, ptr %2, ptr null)
call void @_QQmain()
call void @_FortranAProgramEndStatement()
ret i32 0
}

attributes #0 = { "frame-pointer"="all" "target-cpu"="x86-64" }
attributes #1 = { "frame-pointer"="all" }

!llvm.ident = !{!0}
!llvm.module.flags = !{!1, !2, !3}

!0 = !{!"flang version 22.0.0 (https://github.com/llvm/llvm-project.git e1afe25356b8d2ee14f5f88bdb6c2a1526ed14ef)"}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 8, !"PIC Level", i32 2}
!3 = !{i32 7, !"PIE Level", i32 2}
5 changes: 5 additions & 0 deletions llvm/tools/llvm-readobj/ELFDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,8 @@ ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
return CreateErr("SHN_ABS");
if (Ndx == ELF::SHN_COMMON)
return CreateErr("SHN_COMMON");
if (Ndx == ELF::SHN_AMD64_LCOMMON)
return CreateErr("SHN_AMD64_LCOMMON");
return CreateErr("SHN_LORESERVE", Ndx - SHN_LORESERVE);
}

Expand Down Expand Up @@ -4308,6 +4310,9 @@ std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(
default:
// Find if:
// Processor specific
if (this->Obj.getHeader().e_machine == EM_X86_64 &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect to see explicit llvm-readobj tests (i.e. located under test/tools/llvm-readobj) for the new code in ELFDumper.cpp, testing its behaviour. This likely would require yaml2obj support and should be in its own PR (together with the functional llvm-readobj changes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @jh7370. I'll create a separate PR for the llvm-readobj change and add the tests.

SectionIndex == ELF::SHN_AMD64_LCOMMON)
return "LARGE_COMMON";
if (SectionIndex >= ELF::SHN_LOPROC && SectionIndex <= ELF::SHN_HIPROC)
return std::string("PRC[0x") +
to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
Expand Down