Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1339,7 +1339,7 @@ // as RelaIplt have. And we still want to emit proper dynamic tags for that // case, so here we always use RelaPlt as marker for the begining of // .rel[a].plt section. - if (IsMain && In.RelaPlt->getParent()->isLive()) { + if (IsMain && (In.RelaPlt->isNeeded() || In.RelaIplt->isNeeded())) { addInSec(DT_JMPREL, In.RelaPlt); Entries.push_back({DT_PLTRELSZ, addPltRelSz}); switch (Config->EMachine) { Index: test/ELF/empty-relaplt-dyntags.test =================================================================== --- /dev/null +++ test/ELF/empty-relaplt-dyntags.test @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o + +# RUN: ld.lld -shared %t.o -T %s -o %t +# RUN: llvm-readobj --dynamic-table %t | FileCheck %s + +## In spite of .rela.plt is empty, it might have been preserved because it is +## mentioned in the linker script. However, even in that case we should not +## produce DT_JMPREL and DT_PLTGOT tags because this can cause a dynamic loader +## to write into memory it considers reserved. In fact, as .got.plt is also +## empty, that memory might be allocated for something else. + +# CHECK: DynamicSection [ +# CHECK-NOT: JMPREL +# CHECK-NOT: PLTGOT + +PHDRS { + all PT_LOAD; + dyn PT_DYNAMIC; +} +SECTIONS { + .rela.plt : { *(.rela.plt) }: all + .dynamic : { *(.dynamic) }: all : dyn +}