Index: lld/ELF/Writer.cpp --- lld/ELF/Writer.cpp.orig +++ lld/ELF/Writer.cpp @@ -243,6 +243,7 @@ void elf::addReservedSymbols() { }; ElfSym::bss = add("__bss_start", 0); + ElfSym::data = add("__data_start", 0); ElfSym::end1 = add("end", -1); ElfSym::end2 = add("_end", -1); ElfSym::etext1 = add("etext", -1); @@ -494,6 +495,12 @@ template void elf::createSyntheticSection in.ibtPlt = std::make_unique(); add(*in.ibtPlt); } +#ifdef __OpenBSD__ + else if (config->emachine == EM_X86_64) { + in.ibtPlt = std::make_unique(); + add(*in.ibtPlt); + } +#endif if (config->emachine == EM_PPC) in.plt = std::make_unique(); @@ -665,7 +672,7 @@ static bool shouldKeepInSymtab(const Defined &sym) { // * --discard-locals is used. // * The symbol is in a SHF_MERGE section, which is normally the reason for // the assembler keeping the .L symbol. - if (sym.getName().starts_with(".L") && + if ((sym.getName().startswith(".L") || sym.getName().empty()) && (config->discard == DiscardPolicy::Locals || (sym.section && (sym.section->flags & SHF_MERGE)))) return false; @@ -811,7 +818,11 @@ static bool isRelroSection(const OutputSection *sec) { // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. if (sec == in.gotPlt->getParent()) +#ifndef __OpenBSD__ return config->zNow; +#else + return true; /* kbind(2) means we can always put these in RELRO */ +#endif // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put @@ -1083,6 +1094,9 @@ template void Writer::setReservedSy ElfSym::bss->section = sbss ? sbss : findSection(".bss"); } + if (ElfSym::data) + ElfSym::data->section = findSection(".data"); + // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (ElfSym::mipsGp) { @@ -2398,11 +2412,22 @@ SmallVector Writer::createPhdrs( addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); + // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes + // the dynamic linker fill the segment with zero data, like bss, but + // it can be treated differently. + if (OutputSection *cmd = findSection(".openbsd.mutable", partNo)) + addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd); + // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo)) addHdr(PT_OPENBSD_RANDOMIZE, cmd->getPhdrFlags())->add(cmd); + // PT_OPENBSD_SYSCALLS is an OpenBSD-specific feature. That makes + // the kernel and dynamic linker register system call sites. + if (OutputSection *cmd = findSection(".openbsd.syscalls", partNo)) + addHdr(PT_OPENBSD_SYSCALLS, cmd->getPhdrFlags())->add(cmd); + if (config->zGnustack != GnuStackKind::None) { // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. If you really want an executable @@ -2421,6 +2446,11 @@ SmallVector Writer::createPhdrs( if (config->zWxneeded) addHdr(PT_OPENBSD_WXNEEDED, PF_X); + // PT_OPENBSD_NOBTCFI is an OpenBSD-specific header to mark that the + // executable is expected to violate branch-target CFI checks. + if (config->zNoBtCfi) + addHdr(PT_OPENBSD_NOBTCFI, PF_X); + if (OutputSection *cmd = findSection(".note.gnu.property", partNo)) addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); @@ -2513,6 +2543,31 @@ template void Writer::fixSectionAli }; } }; + +#ifdef __OpenBSD__ + // On i386, produce binaries that are compatible with our W^X implementation + if (config->emachine == EM_386) { + auto NXAlign = [](OutputSection *Cmd) { + if (Cmd && !Cmd->addrExpr) + Cmd->addrExpr = [=] { + return alignTo(script->getDot(), 0x20000000); + }; + }; + + for (Partition &part : partitions) { + PhdrEntry *firstRW = nullptr; + for (PhdrEntry *P : part.phdrs) { + if (P->p_type == PT_LOAD && (P->p_flags & PF_W)) { + firstRW = P; + break; + } + } + + if (firstRW) + NXAlign(firstRW->firstSec); + } + } +#endif for (Partition &part : partitions) { prev = nullptr;