@@ -71,10 +71,15 @@ import (
7171// ElfEhdr is the ELF file header.
7272type ElfEhdr elf.Header64
7373
74- // ElfShdr is an ELF section entry, plus the section index .
74+ // ElfShdr is an ELF section table entry .
7575type ElfShdr struct {
7676 elf.Section64
7777
78+ // nameString is the section name as a string.
79+ // This is not to be confused with Name,
80+ // inherited from elf.Section64, which is an offset.
81+ nameString string
82+
7883 // The section index, set by elfSortShdrs.
7984 // Don't read this directly, use elfShdrShnum.
8085 shnum elf.SectionIndex
@@ -109,7 +114,7 @@ const (
109114 ELF32RELSIZE = 8
110115)
111116
112- var elfstrdat , elfshstrdat []byte
117+ var elfstrdat []byte
113118
114119// ELFRESERVE is the total amount of space to reserve at the
115120// start of the file for Header, PHeaders, SHeaders, and interp.
@@ -158,15 +163,6 @@ type ELFArch struct {
158163 DynamicReadOnly bool
159164}
160165
161- type Elfstring struct {
162- s string
163- off int
164- }
165-
166- var elfstr [100 ]Elfstring
167-
168- var nelfstr int
169-
170166var buildinfo []byte
171167
172168// Elfinit initializes the global ehdr variable that holds the ELF header.
@@ -413,15 +409,46 @@ func elfSortShdrs(ctxt *Link) {
413409 shdrSorted = true
414410}
415411
416- func elfsetstring (ctxt * Link , s loader.Sym , str string , off int ) {
417- if nelfstr >= len (elfstr ) {
418- ctxt .Errorf (s , "too many elf strings" )
419- errorexit ()
412+ // elfWriteShstrtab writes out the ELF section string table.
413+ // It also sets the Name field of the section headers.
414+ // It returns the length of the string table.
415+ func elfWriteShstrtab (ctxt * Link ) uint32 {
416+ // Map from section name to shstrtab offset.
417+ m := make (map [string ]uint32 , len (shdr ))
418+
419+ m ["" ] = 0
420+ ctxt .Out .WriteByte (0 )
421+ off := uint32 (1 )
422+
423+ writeString := func (s string ) {
424+ m [s ] = off
425+ ctxt .Out .WriteString (s )
426+ ctxt .Out .WriteByte (0 )
427+ off += uint32 (len (s )) + 1
428+ }
429+
430+ // As a minor optimization, do the relocation sections first,
431+ // as they may let us reuse the suffix.
432+ // That is, the offset for ".text" can point into ".rel.text".
433+ // We don't do a full suffix search as the relocation sections
434+ // are likely to be the only match.
435+ for _ , sh := range shdr {
436+ if suffix , ok := strings .CutPrefix (sh .nameString , elfRelType ); ok {
437+ m [suffix ] = off + uint32 (len (elfRelType ))
438+ writeString (sh .nameString )
439+ }
440+ }
441+
442+ for _ , sh := range shdr {
443+ if shOff , ok := m [sh .nameString ]; ok {
444+ sh .Name = shOff
445+ } else {
446+ sh .Name = off
447+ writeString (sh .nameString )
448+ }
420449 }
421450
422- elfstr [nelfstr ].s = str
423- elfstr [nelfstr ].off = off
424- nelfstr ++
451+ return off
425452}
426453
427454func elfwritephdrs (out * OutBuf ) uint32 {
@@ -450,15 +477,16 @@ func newElfPhdr() *ElfPhdr {
450477 return e
451478}
452479
453- func newElfShdr (name int64 ) * ElfShdr {
480+ func newElfShdr (name string ) * ElfShdr {
454481 if shdrSorted {
455482 Errorf ("internal error: creating a section header after they were sorted" )
456483 errorexit ()
457484 }
458485
459- e := new (ElfShdr )
460- e .Name = uint32 (name )
461- e .shnum = - 1 // make invalid for now, set by elfSortShdrs
486+ e := & ElfShdr {
487+ nameString : name ,
488+ shnum : - 1 , // make invalid for now, set by elfSortShdrs
489+ }
462490 shdr = append (shdr , e )
463491 return e
464492}
@@ -1165,36 +1193,20 @@ func elfphrelro(seg *sym.Segment) {
11651193 ph .Align = uint64 (* FlagRound )
11661194}
11671195
1196+ // elfshname finds or creates a section given its name.
11681197func elfshname (name string ) * ElfShdr {
1169- for i := 0 ; i < nelfstr ; i ++ {
1170- if name != elfstr [i ].s {
1171- continue
1172- }
1173- off := elfstr [i ].off
1174- for _ , sh := range shdr {
1175- if sh .Name == uint32 (off ) {
1176- return sh
1177- }
1198+ for _ , sh := range shdr {
1199+ if sh .nameString == name {
1200+ return sh
11781201 }
1179- return newElfShdr (int64 (off ))
11801202 }
1181- Exitf ("cannot find elf name %s" , name )
1182- return nil
1203+ return newElfShdr (name )
11831204}
11841205
1185- // Create an ElfShdr for the section with name.
1186- // Create a duplicate if one already exists with that name.
1206+ // elfshnamedup creates a new section with a given name.
1207+ // If there is an existing section with this name, it creates a duplicate .
11871208func elfshnamedup (name string ) * ElfShdr {
1188- for i := 0 ; i < nelfstr ; i ++ {
1189- if name == elfstr [i ].s {
1190- off := elfstr [i ].off
1191- return newElfShdr (int64 (off ))
1192- }
1193- }
1194-
1195- Errorf ("cannot find elf name %s" , name )
1196- errorexit ()
1197- return nil
1209+ return newElfShdr (name )
11981210}
11991211
12001212func elfshalloc (sect * sym.Section ) * ElfShdr {
@@ -1446,140 +1458,11 @@ func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
14461458func (ctxt * Link ) doelf () {
14471459 ldr := ctxt .loader
14481460
1449- // Predefine strings we need for section headers.
1450-
1451- addshstr := func (s string ) int {
1452- off := len (elfshstrdat )
1453- elfshstrdat = append (elfshstrdat , s ... )
1454- elfshstrdat = append (elfshstrdat , 0 )
1455- return off
1456- }
1457-
1458- shstrtabAddstring := func (s string ) {
1459- off := addshstr (s )
1460- elfsetstring (ctxt , 0 , s , off )
1461- }
1462-
1463- shstrtabAddstring ("" )
1464- shstrtabAddstring (".text" )
1465- shstrtabAddstring (".noptrdata" )
1466- shstrtabAddstring (".data" )
1467- shstrtabAddstring (".bss" )
1468- shstrtabAddstring (".noptrbss" )
1469- shstrtabAddstring (".go.fuzzcntrs" )
1470- shstrtabAddstring (".go.buildinfo" )
1471- shstrtabAddstring (".go.fipsinfo" )
1472- if ctxt .IsMIPS () {
1473- shstrtabAddstring (".MIPS.abiflags" )
1474- shstrtabAddstring (".gnu.attributes" )
1475- }
1476-
1477- // generate .tbss section for dynamic internal linker or external
1478- // linking, so that various binutils could correctly calculate
1479- // PT_TLS size. See https://golang.org/issue/5200.
1480- if ! * FlagD || ctxt .IsExternal () {
1481- shstrtabAddstring (".tbss" )
1482- }
1483- if ctxt .IsNetbsd () {
1484- shstrtabAddstring (".note.netbsd.ident" )
1485- if * flagRace {
1486- shstrtabAddstring (".note.netbsd.pax" )
1487- }
1488- }
1489- if ctxt .IsOpenbsd () {
1490- shstrtabAddstring (".note.openbsd.ident" )
1491- }
1492- if ctxt .IsFreebsd () {
1493- shstrtabAddstring (".note.tag" )
1494- }
1495- if len (buildinfo ) > 0 {
1496- shstrtabAddstring (".note.gnu.build-id" )
1497- }
1498- if * flagBuildid != "" {
1499- shstrtabAddstring (".note.go.buildid" )
1500- }
1501- shstrtabAddstring (".elfdata" )
1502- shstrtabAddstring (".rodata" )
1503- shstrtabAddstring (".gopclntab" )
1504- // See the comment about data.rel.ro.FOO section names in data.go.
1505- relro_prefix := ""
1506- if ctxt .UseRelro () {
1507- shstrtabAddstring (".data.rel.ro" )
1508- relro_prefix = ".data.rel.ro"
1509- }
1510- shstrtabAddstring (relro_prefix + ".typelink" )
1511- shstrtabAddstring (relro_prefix + ".itablink" )
1512-
15131461 if ctxt .IsExternal () {
15141462 * FlagD = true
1515-
1516- shstrtabAddstring (elfRelType + ".text" )
1517- shstrtabAddstring (elfRelType + ".rodata" )
1518- shstrtabAddstring (elfRelType + relro_prefix + ".typelink" )
1519- shstrtabAddstring (elfRelType + relro_prefix + ".itablink" )
1520- shstrtabAddstring (elfRelType + ".noptrdata" )
1521- shstrtabAddstring (elfRelType + ".data" )
1522- if ctxt .UseRelro () {
1523- shstrtabAddstring (elfRelType + ".data.rel.ro" )
1524- }
1525- shstrtabAddstring (elfRelType + ".go.buildinfo" )
1526- shstrtabAddstring (elfRelType + ".go.fipsinfo" )
1527- if ctxt .IsMIPS () {
1528- shstrtabAddstring (elfRelType + ".MIPS.abiflags" )
1529- shstrtabAddstring (elfRelType + ".gnu.attributes" )
1530- }
1531-
1532- // add a .note.GNU-stack section to mark the stack as non-executable
1533- shstrtabAddstring (".note.GNU-stack" )
1534-
1535- if ctxt .IsShared () {
1536- shstrtabAddstring (".note.go.abihash" )
1537- shstrtabAddstring (".note.go.pkg-list" )
1538- shstrtabAddstring (".note.go.deps" )
1539- }
1540- }
1541-
1542- hasinitarr := ctxt .linkShared
1543-
1544- // Shared library initializer.
1545- switch ctxt .BuildMode {
1546- case BuildModeCArchive , BuildModeCShared , BuildModeShared , BuildModePlugin :
1547- hasinitarr = true
1548- }
1549-
1550- if hasinitarr {
1551- shstrtabAddstring (".init_array" )
1552- shstrtabAddstring (elfRelType + ".init_array" )
1553- }
1554-
1555- if ! * FlagS {
1556- shstrtabAddstring (".symtab" )
1557- shstrtabAddstring (".strtab" )
15581463 }
1559- if ! * FlagW {
1560- dwarfaddshstrings (ctxt , shstrtabAddstring )
1561- }
1562-
1563- shstrtabAddstring (".shstrtab" )
15641464
15651465 if ! * FlagD { // -d suppresses dynamic loader format
1566- shstrtabAddstring (".interp" )
1567- shstrtabAddstring (".hash" )
1568- shstrtabAddstring (".got" )
1569- if ctxt .IsPPC64 () {
1570- shstrtabAddstring (".glink" )
1571- }
1572- shstrtabAddstring (".got.plt" )
1573- shstrtabAddstring (".dynamic" )
1574- shstrtabAddstring (".dynsym" )
1575- shstrtabAddstring (".dynstr" )
1576- shstrtabAddstring (elfRelType )
1577- shstrtabAddstring (elfRelType + ".plt" )
1578-
1579- shstrtabAddstring (".plt" )
1580- shstrtabAddstring (".gnu.version" )
1581- shstrtabAddstring (".gnu.version_r" )
1582-
15831466 // dynamic symbol table - first entry all zeros
15841467 dynsym := ldr .CreateSymForUpdate (".dynsym" , 0 )
15851468
@@ -2291,13 +2174,14 @@ elfobj:
22912174 sh := elfshname (".shstrtab" )
22922175 eh .Shstrndx = uint16 (elfShdrShnum (sh ))
22932176
2177+ var shstrtabLen uint32
22942178 ctxt .Out .SeekSet (symo )
22952179 if * FlagS {
2296- ctxt . Out . Write ( elfshstrdat )
2180+ shstrtabLen = elfWriteShstrtab ( ctxt )
22972181 } else {
22982182 asmElfSym (ctxt )
22992183 ctxt .Out .Write (elfstrdat )
2300- ctxt . Out . Write ( elfshstrdat )
2184+ shstrtabLen = elfWriteShstrtab ( ctxt )
23012185 if ctxt .IsExternal () {
23022186 elfEmitReloc (ctxt )
23032187 }
@@ -2328,7 +2212,7 @@ elfobj:
23282212 sh = elfshname (".shstrtab" )
23292213 sh .Type = uint32 (elf .SHT_STRTAB )
23302214 sh .Off = shstroff
2331- sh .Size = uint64 (len ( elfshstrdat ) )
2215+ sh .Size = uint64 (shstrtabLen )
23322216 sh .Addralign = 1
23332217
23342218 // Main header
0 commit comments