[llvm] [MC] Fix elf symbol info (PR #226834)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 27 13:41:22 PDT 2026


https://github.com/rdong8 created https://github.com/llvm/llvm-project/pull/226834

https://github.com/llvm/llvm-project/blob/32080ffd98b12a7f4733181790b21ff62f9f31ba/llvm/lib/MC/ELFObjectWriter.cpp#L613

Here `ELF::STT_FILE` and `ELF::STB_LOCAL` are enumerators corresponding to different enums. This is seemingly a latent bug since the same file shows the correct way to compute this:

https://github.com/llvm/llvm-project/blob/32080ffd98b12a7f4733181790b21ff62f9f31ba/llvm/lib/MC/ELFObjectWriter.cpp#L426

These two ways happen to give the same value right now only because `ELF::STB_LOCAL == 0`. I added a helper function to compute this.

This issue was found with the help of AI while working on https://github.com/llvm/llvm-project/pull/223284

>From 72c61ac51ca575566c0a2790081f305a675bc214 Mon Sep 17 00:00:00 2001
From: Richard Dong <66289396+rdong8 at users.noreply.github.com>
Date: Sun, 20 Sep 2026 18:18:32 +0000
Subject: [PATCH 1/2] [MC] Fix ELF symbol info computation

---
 llvm/lib/MC/ELFObjectWriter.cpp | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 3af4851d39d94..d57b1abf6f5c1 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -406,6 +406,10 @@ static bool isIFunc(const MCSymbolELF *Symbol) {
   return true;
 }
 
+static uint8_t getSymbolInfo(uint8_t Binding, uint8_t Type) {
+  return (Binding << 4) | (Type & 0x0f);
+}
+
 void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
                             ELFSymbolData &MSD) {
   auto &Symbol = static_cast<const MCSymbolELF &>(*MSD.Symbol);
@@ -423,7 +427,7 @@ void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
   if (Base) {
     Type = mergeTypeForSet(Type, Base->getType());
   }
-  uint8_t Info = (Binding << 4) | Type;
+  uint8_t Info = getSymbolInfo(Binding, Type);
 
   // Other and Visibility share the same byte with Visibility using the lower
   // 2 bits
@@ -610,8 +614,8 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
     for (; FileNameIt != FileNames.end() && FileNameIt->second <= MSD.Order;
          ++FileNameIt) {
       Writer.writeSymbol(StrTabBuilder.getOffset(FileNameIt->first),
-                         ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT,
-                         ELF::SHN_ABS, true);
+                         getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0, 0,
+                         ELF::STV_DEFAULT, ELF::SHN_ABS, true);
       ++Index;
     }
 
@@ -623,8 +627,8 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
   }
   for (; FileNameIt != FileNames.end(); ++FileNameIt) {
     Writer.writeSymbol(StrTabBuilder.getOffset(FileNameIt->first),
-                       ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT,
-                       ELF::SHN_ABS, true);
+                       getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0, 0,
+                       ELF::STV_DEFAULT, ELF::SHN_ABS, true);
     ++Index;
   }
 

>From 77f6ed725ff041b69fbbb3c8fd7d9a3d63c5f4b8 Mon Sep 17 00:00:00 2001
From: Richard Dong <66289396+rdong8 at users.noreply.github.com>
Date: Sun, 27 Sep 2026 20:08:40 +0000
Subject: [PATCH 2/2] [BinaryFormat][MC] Use shared getSymbolInfo helper across
 ELF.h, ELFTypes.h, and ELFObjectWriter

---
 llvm/include/llvm/BinaryFormat/ELF.h |  9 +++++++--
 llvm/include/llvm/Object/ELFTypes.h  |  2 +-
 llvm/lib/MC/ELFObjectWriter.cpp      | 12 ++++--------
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 6bb387799c4a1..9bae08ba51545 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1364,6 +1364,11 @@ enum : unsigned {
   GRP_MASKPROC = 0xf0000000
 };
 
+// Corresponds to the ELF32_ST_INFO / ELF64_ST_INFO macro
+inline uint8_t getSymbolInfo(uint8_t Binding, uint8_t Type) {
+  return (Binding << 4) | (Type & 0x0f);
+}
+
 // Symbol table entries for ELF32.
 struct Elf32_Sym {
   Elf32_Word st_name;     // Symbol name (index into string table)
@@ -1380,7 +1385,7 @@ struct Elf32_Sym {
   void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
   void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
   void setBindingAndType(unsigned char b, unsigned char t) {
-    st_info = (b << 4) + (t & 0x0f);
+    st_info = getSymbolInfo(b, t);
   }
 };
 
@@ -1400,7 +1405,7 @@ struct Elf64_Sym {
   void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
   void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
   void setBindingAndType(unsigned char b, unsigned char t) {
-    st_info = (b << 4) + (t & 0x0f);
+    st_info = getSymbolInfo(b, t);
   }
 };
 
diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 6d5a0bdb21130..925e800495d78 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -244,7 +244,7 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
   void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
 
   void setBindingAndType(unsigned char b, unsigned char t) {
-    st_info = (b << 4) + (t & 0x0f);
+    st_info = ELF::getSymbolInfo(b, t);
   }
 
   /// Access to the STV_xxx flag stored in the first two bits of st_other.
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index d57b1abf6f5c1..6e52fcbdbb0fe 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -406,10 +406,6 @@ static bool isIFunc(const MCSymbolELF *Symbol) {
   return true;
 }
 
-static uint8_t getSymbolInfo(uint8_t Binding, uint8_t Type) {
-  return (Binding << 4) | (Type & 0x0f);
-}
-
 void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
                             ELFSymbolData &MSD) {
   auto &Symbol = static_cast<const MCSymbolELF &>(*MSD.Symbol);
@@ -427,7 +423,7 @@ void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
   if (Base) {
     Type = mergeTypeForSet(Type, Base->getType());
   }
-  uint8_t Info = getSymbolInfo(Binding, Type);
+  uint8_t Info = ELF::getSymbolInfo(Binding, Type);
 
   // Other and Visibility share the same byte with Visibility using the lower
   // 2 bits
@@ -614,8 +610,8 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
     for (; FileNameIt != FileNames.end() && FileNameIt->second <= MSD.Order;
          ++FileNameIt) {
       Writer.writeSymbol(StrTabBuilder.getOffset(FileNameIt->first),
-                         getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0, 0,
-                         ELF::STV_DEFAULT, ELF::SHN_ABS, true);
+                         ELF::getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0,
+                         0, ELF::STV_DEFAULT, ELF::SHN_ABS, true);
       ++Index;
     }
 
@@ -627,7 +623,7 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
   }
   for (; FileNameIt != FileNames.end(); ++FileNameIt) {
     Writer.writeSymbol(StrTabBuilder.getOffset(FileNameIt->first),
-                       getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0, 0,
+                       ELF::getSymbolInfo(ELF::STB_LOCAL, ELF::STT_FILE), 0, 0,
                        ELF::STV_DEFAULT, ELF::SHN_ABS, true);
     ++Index;
   }



More information about the llvm-commits mailing list