mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
ELF: Use index 0 for unversioned undefined symbols (#168189)
The GNU documentation is ambiguous about the version index for unversioned undefined symbols. The current specification at https://sourceware.org/gnu-gabi/program-loading-and-dynamic-linking.txt defines VER_NDX_LOCAL (0) as "The symbol is private, and is not available outside this object." However, this naming is misleading for undefined symbols. As suggested in discussions, VER_NDX_LOCAL should conceptually be VER_NDX_NONE and apply to unversioned undefined symbols as well. GNU ld has used index 0 for unversioned undefined symbols both before version 2.35 (see https://sourceware.org/PR26002) and in the upcoming 2.46 release (see https://sourceware.org/PR33577). This change aligns with GNU ld's behavior by switching from index 1 to index 0. While here, add a test to dso-undef-extract-lazy.s that undefined symbols of index 0 in DSO are treated as unversioned symbols.
This commit is contained in:
@@ -1676,8 +1676,9 @@ template <class ELFT> void SharedFile::parse() {
|
||||
|
||||
const uint16_t ver = versyms[i], idx = ver & ~VERSYM_HIDDEN;
|
||||
if (sym.isUndefined()) {
|
||||
// For unversioned undefined symbols, VER_NDX_GLOBAL makes more sense but
|
||||
// as of binutils 2.34, GNU ld produces VER_NDX_LOCAL.
|
||||
// Index 0 (VER_NDX_LOCAL) is used for unversioned undefined symbols.
|
||||
// GNU ld versions between 2.35 and 2.45 also generate VER_NDX_GLOBAL
|
||||
// for this case (https://sourceware.org/PR33577).
|
||||
if (ver != VER_NDX_LOCAL && ver != VER_NDX_GLOBAL) {
|
||||
if (idx >= verneeds.size()) {
|
||||
ErrAlways(ctx) << "corrupt input file: version need index " << idx
|
||||
|
||||
@@ -313,6 +313,8 @@ public:
|
||||
// represents the Verdef index within the input DSO, which will be converted
|
||||
// to a Verneed index in the output. Otherwise, this represents the Verdef
|
||||
// index (VER_NDX_LOCAL, VER_NDX_GLOBAL, or a named version).
|
||||
// VER_NDX_LOCAL indicates a defined symbol that has been localized by a
|
||||
// version script's local: directive or --exclude-libs.
|
||||
uint16_t versionId;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
uint8_t versionScriptAssigned : 1;
|
||||
|
||||
@@ -3784,9 +3784,10 @@ void VersionTableSection::writeTo(uint8_t *buf) {
|
||||
buf += 2;
|
||||
for (const SymbolTableEntry &s : getPartition(ctx).dynSymTab->getSymbols()) {
|
||||
// For an unextracted lazy symbol (undefined weak), it must have been
|
||||
// converted to Undefined and have VER_NDX_GLOBAL version here.
|
||||
// converted to Undefined.
|
||||
assert(!s.sym->isLazy());
|
||||
write16(ctx, buf, s.sym->versionId);
|
||||
// Undefined symbols should use index 0 when unversioned.
|
||||
write16(ctx, buf, s.sym->isUndefined() ? 0 : s.sym->versionId);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Version: 1
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: Name: und
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Version: 1
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: Name: _Z3abbi
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
@@ -1710,8 +1710,8 @@ enum { VER_FLG_BASE = 0x1, VER_FLG_WEAK = 0x2, VER_FLG_INFO = 0x4 };
|
||||
|
||||
// Special constants for the version table. (SHT_GNU_versym/.gnu.version)
|
||||
enum {
|
||||
VER_NDX_LOCAL = 0, // Unversioned local symbol
|
||||
VER_NDX_GLOBAL = 1, // Unversioned global symbol
|
||||
VER_NDX_LOCAL = 0, // Unversioned undefined or localized defined symbol
|
||||
VER_NDX_GLOBAL = 1, // Unversioned non-local defined symbol
|
||||
VERSYM_VERSION = 0x7fff, // Version Index mask
|
||||
VERSYM_HIDDEN = 0x8000 // Hidden bit (non-default version)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user