[lld] [llvm] [LLD][ELF] Support for SHN_AMD64_LCOMMON and lbss on x86-64 (PR #161697)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 2 09:41:24 PDT 2025


https://github.com/ssijaric-nv created https://github.com/llvm/llvm-project/pull/161697

Place LARGE_COMMON (SHN_AMD64_LCOMMON) into lbss on x86-64.  Needed to
support large Fortran common blocks with medium and large code models on
x86-64:

Sections:
...
25 .lbss         b44834508  0000000000004060  0000000000004060  0000304c  2**3
                 ALLOC
...
SYMBOL TABLE:
...
0000000000004060 g     O .lbss  0000000b44834508              __BLNK__

where __BLNK__ is a large common block resulting from:

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

There is a sperate PR for emitting SHN_AMD64_LCOMMON.


>From 9cdc2dba013e4360288c88656f4ea4a539677362 Mon Sep 17 00:00:00 2001
From: Sanjin Sijaric <ssijaric at nvidia.com>
Date: Wed, 1 Oct 2025 15:50:07 -0700
Subject: [PATCH] [LLD][ELF] Support for SHN_AMD64_LCOMMON and lbss on x86-64

Place LARGE_COMMON (SHN_AMD64_LCOMMON) into lbss on x86-64.  Needed to
support large Fortran common blocks with medium and large code models on
x86-64:

Sections:
...
25 .lbss         b44834508  0000000000004060  0000000000004060  0000304c  2**3
                 ALLOC
...
SYMBOL TABLE:
...
0000000000004060 g     O .lbss  0000000b44834508              __BLNK__

where __BLNK__ is a large common block resulting from:

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

There is a sperate PR for emitting SHN_AMD64_LCOMMON.
---
 lld/ELF/Driver.cpp                   |  5 ++++-
 lld/ELF/InputFiles.cpp               |  8 ++++++--
 lld/ELF/InputSection.cpp             |  2 +-
 lld/ELF/InputSection.h               |  1 +
 lld/ELF/LinkerScript.cpp             |  6 +++++-
 lld/ELF/Symbols.h                    |  8 +++++---
 lld/ELF/SyntheticSections.cpp        |  6 ++++++
 lld/ELF/SyntheticSections.h          | 13 ++++++++++++-
 llvm/include/llvm/BinaryFormat/ELF.h |  5 +++++
 9 files changed, 45 insertions(+), 9 deletions(-)

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<BssSection>(ctx, "COMMON", s->size, s->alignment);
+      auto *bss =
+          (s->isLargeCommon)
+              ? make<LbssSection>(ctx, "LARGE_COMMON", s->size, s->alignment)
+              : make<BssSection>(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<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &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<CommonSymbol &>(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<SyntheticSection>(s) && cast<SyntheticSection>(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"



More information about the llvm-commits mailing list