Skip to content

Commit 5d972c5

Browse files
authored
[ELF] Add -z nosectionheader
GNU ld since 2.41 supports this option, which is mildly useful. It omits the section header table and non-ALLOC sections (including .symtab/.strtab (--strip-all)). This option is simple to implement and might be used by LLDB to test program headers parsing without the section header table (#100900). -z sectionheader, which is the default, is also added. Pull Request: #101286
1 parent 2bf58f5 commit 5d972c5

File tree

8 files changed

+65
-5
lines changed

8 files changed

+65
-5
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ struct Config {
333333
bool zPacPlt;
334334
bool zRelro;
335335
bool zRodynamic;
336+
bool zSectionHeader;
336337
bool zShstk;
337338
bool zStartStopGC;
338339
uint8_t zStartStopVisibility;

lld/ELF/Driver.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ static void checkOptions() {
447447
error("-r and --export-dynamic may not be used together");
448448
if (config->debugNames)
449449
error("-r and --debug-names may not be used together");
450+
if (!config->zSectionHeader)
451+
error("-r and -z nosectionheader may not be used together");
450452
}
451453

452454
if (config->executeOnly) {
@@ -836,6 +838,8 @@ static ICFLevel getICF(opt::InputArgList &args) {
836838
static StripPolicy getStrip(opt::InputArgList &args) {
837839
if (args.hasArg(OPT_relocatable))
838840
return StripPolicy::None;
841+
if (!config->zSectionHeader)
842+
return StripPolicy::All;
839843

840844
auto *arg = args.getLastArg(OPT_strip_all, OPT_strip_debug);
841845
if (!arg)
@@ -1411,7 +1415,9 @@ static void readConfigs(opt::InputArgList &args) {
14111415
config->soName = args.getLastArgValue(OPT_soname);
14121416
config->sortSection = getSortSection(args);
14131417
config->splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384);
1414-
config->strip = getStrip(args);
1418+
config->zSectionHeader =
1419+
getZFlag(args, "sectionheader", "nosectionheader", true);
1420+
config->strip = getStrip(args); // needs zSectionHeader
14151421
config->sysroot = args.getLastArgValue(OPT_sysroot);
14161422
config->target1Rel = args.hasFlag(OPT_target1_rel, OPT_target1_abs, false);
14171423
config->target2 = getTarget2(args);

lld/ELF/SyntheticSections.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4665,7 +4665,8 @@ template <class ELFT> void elf::createSyntheticSections() {
46654665

46664666
auto add = [](SyntheticSection &sec) { ctx.inputSections.push_back(&sec); };
46674667

4668-
in.shStrTab = std::make_unique<StringTableSection>(".shstrtab", false);
4668+
if (config->zSectionHeader)
4669+
in.shStrTab = std::make_unique<StringTableSection>(".shstrtab", false);
46694670

46704671
Out::programHeaders = make<OutputSection>("", 0, SHF_ALLOC);
46714672
Out::programHeaders->addralign = config->wordsize;
@@ -4917,7 +4918,8 @@ template <class ELFT> void elf::createSyntheticSections() {
49174918
add(*in.symTab);
49184919
if (in.symTabShndx)
49194920
add(*in.symTabShndx);
4920-
add(*in.shStrTab);
4921+
if (in.shStrTab)
4922+
add(*in.shStrTab);
49214923
if (in.strTab)
49224924
add(*in.strTab);
49234925
}

lld/ELF/Writer.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,13 +1875,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
18751875
sortSections();
18761876

18771877
// Create a list of OutputSections, assign sectionIndex, and populate
1878-
// in.shStrTab.
1878+
// in.shStrTab. If -z nosectionheader is specified, drop non-ALLOC sections.
18791879
for (SectionCommand *cmd : script->sectionCommands)
18801880
if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
18811881
OutputSection *osec = &osd->osec;
1882+
if (!in.shStrTab && !(osec->flags & SHF_ALLOC))
1883+
continue;
18821884
outputSections.push_back(osec);
18831885
osec->sectionIndex = outputSections.size();
1884-
osec->shName = in.shStrTab->addString(osec->name);
1886+
if (in.shStrTab)
1887+
osec->shName = in.shStrTab->addString(osec->name);
18851888
}
18861889

18871890
// Prefer command line supplied address over other constraints.
@@ -2703,6 +2706,10 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
27032706
auto *eHdr = reinterpret_cast<Elf_Ehdr *>(Out::bufferStart);
27042707
eHdr->e_type = getELFType();
27052708
eHdr->e_entry = getEntryAddr();
2709+
2710+
// If -z nosectionheader is specified, omit the section header table.
2711+
if (!in.shStrTab)
2712+
return;
27062713
eHdr->e_shoff = sectionHeaderOff;
27072714

27082715
// Write the section header table.

lld/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Non-comprehensive list of changes in this release
2626
ELF Improvements
2727
----------------
2828

29+
* ``-z nosectionheader`` has been implemented to omit the section header table.
30+
The operation is similar to ``llvm-objcopy --strip-sections``.
31+
(`#101286 <https://github.com/llvm/llvm-project/pull/101286>`_)
32+
2933
Breaking changes
3034
----------------
3135

lld/docs/ld.lld.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,9 @@ The object will omit the
857857
.Dv PT_GNU_RELRO
858858
segment.
859859
.Pp
860+
.It Cm nosectionheader
861+
Don't generate the section header table.
862+
.Pp
860863
.It Cm notext
861864
Allow relocations against read-only segments.
862865
Sets the

lld/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ if (NOT LLD_BUILT_STANDALONE)
6464
llvm-profdata
6565
llvm-readelf
6666
llvm-readobj
67+
llvm-strings
6768
llvm-strip
6869
llvm-symbolizer
6970
not

lld/test/ELF/zsectionheader.s

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
# RUN: ld.lld -shared -z nosectionheader -z sectionheader %t.o -o %t.so 2>&1 | count 0
4+
# RUN: llvm-readelf -hS %t.so | FileCheck %s --check-prefixes=CHECK,SHDR
5+
6+
# RUN: ld.lld -shared -z nosectionheader %t.o -o %t0.so
7+
# RUN: llvm-readelf -h --dyn-syms %t0.so | FileCheck %s --check-prefixes=CHECK,NOSHDR
8+
# RUN: llvm-strings %t0.so | FileCheck %s --check-prefixes=NOSHDR-STR
9+
10+
# CHECK: Size of this header: 64 (bytes)
11+
# CHECK-NEXT: Size of program headers: 56 (bytes)
12+
# CHECK-NEXT: Number of program headers: 6
13+
# CHECK-NEXT: Size of section headers: 64 (bytes)
14+
# SHDR-NEXT: Number of section headers: 13
15+
# SHDR-NEXT: Section header string table index: 11
16+
# NOSHDR-NEXT: Number of section headers: 0
17+
# NOSHDR-NEXT: Section header string table index: 0
18+
19+
# SHDR: Section Headers:
20+
# NOSHDR: Symbol table for image contains 2 entries:
21+
# NOSHDR: _start
22+
23+
## _start occurs as a dynamic string table entry. There is no static string table
24+
## entry. `nonalloc` is not in the output.
25+
# NOSHDR-STR: _start
26+
# NOSHDR-STR-NOT: _start
27+
28+
# RUN: not ld.lld -r -z nosectionheader %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
29+
30+
# ERR: error: -r and -z nosectionheader may not be used together
31+
32+
.globl _start
33+
_start:
34+
35+
.section nonalloc,""
36+
.asciz "_start"

0 commit comments

Comments
 (0)