[lld] [llvm] [LLVM][LLD] Add support for two special OpenBSD sections (PR #97122)

John Ericson via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 9 06:34:42 PDT 2024


https://github.com/Ericson2314 updated https://github.com/llvm/llvm-project/pull/97122

>From bd7871b501c14be71e8671770918bdd82c78ab8d Mon Sep 17 00:00:00 2001
From: John Ericson <John.Ericson at Obsidian.Systems>
Date: Sun, 30 Jun 2024 18:47:58 -0400
Subject: [PATCH 1/4] [LLMV] set OpenBSD's ELFOSABI by default

This matches what is done for FreeBSD.

OpenBSD has a few special program header types, and other such ELF
extensions. Setting the ELFOSABI like so will allow LLD to support them
without needlessly impacting non-OpenBSD ELFs.
---
 llvm/include/llvm/MC/MCELFObjectWriter.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h
index d7c223cdcc07f..12237094ad86a 100644
--- a/llvm/include/llvm/MC/MCELFObjectWriter.h
+++ b/llvm/include/llvm/MC/MCELFObjectWriter.h
@@ -78,6 +78,8 @@ class MCELFObjectTargetWriter : public MCObjectTargetWriter {
         return ELF::ELFOSABI_FREEBSD;
       case Triple::Solaris:
         return ELF::ELFOSABI_SOLARIS;
+      case Triple::OpenBSD:
+        return ELF::ELFOSABI_OPENBSD;
       default:
         return ELF::ELFOSABI_NONE;
     }

>From 0d15857a9f28b9a7f7cf77612733ad83e4401765 Mon Sep 17 00:00:00 2001
From: deraadt <deraadt at openbsd.org>
Date: Fri, 7 Oct 2022 15:04:51 +0000
Subject: [PATCH 2/4] [LLD] Add support for `.openbsd.mutable`

(rebaser's note) adapted from:
https://github.com/openbsd/src/commit/bd249b5664da50f0178adea78250a7a0d8ea6566
New auto-coalescing sections removed

In the linkers, collect objects in section "openbsd.mutable" and place them into a page-aligned region in the bss, with the right markers for kernel/ld.so to identify the region and skip making it immutable. While here, fix readelf/objdump versions to show all of this. ok miod kettenis
---
 lld/ELF/ScriptParser.cpp | 1 +
 lld/ELF/Writer.cpp       | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index db46263115242..b8d18f516f461 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1628,6 +1628,7 @@ unsigned ScriptParser::readPhdrType() {
                      .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
                      .Case("PT_GNU_STACK", PT_GNU_STACK)
                      .Case("PT_GNU_RELRO", PT_GNU_RELRO)
+                     .Case("PT_OPENBSD_MUTABLE", PT_OPENBSD_MUTABLE)
                      .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
                      .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
                      .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index bce3cd2de7ed2..b8d727291caf8 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2273,6 +2273,12 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
     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))

>From 449b3ec117a87c6940827e6dab1fc4ebb8f76bc1 Mon Sep 17 00:00:00 2001
From: kettenis <kettenis at openbsd.org>
Date: Sun, 3 Dec 2023 21:15:11 +0000
Subject: [PATCH 3/4] [LLD] Add support for `.openbsd.syscalls`

(rebaser's note) adapted from:
https://github.com/openbsd/src/commit/42a61acefa8b3288ff2163fb55e934a3fee39974

Collect .openbsd.syscalls sections into a new PT_OPENBSD_SYSCALLS segment. This will be used soon to pin system calls to designated call sites.

ok deraadt@
---
 lld/ELF/ScriptParser.cpp | 1 +
 lld/ELF/Writer.cpp       | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index b8d18f516f461..41bd9a95053f7 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1630,6 +1630,7 @@ unsigned ScriptParser::readPhdrType() {
                      .Case("PT_GNU_RELRO", PT_GNU_RELRO)
                      .Case("PT_OPENBSD_MUTABLE", PT_OPENBSD_MUTABLE)
                      .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
+                     .Case("PT_OPENBSD_SYSCALLS", PT_OPENBSD_SYSCALLS)
                      .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
                      .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
                      .Default(-1);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index b8d727291caf8..efa9383e70726 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2284,6 +2284,11 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
   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

>From f5c3bab68863f2d97ada2e01c1703ae5f4235741 Mon Sep 17 00:00:00 2001
From: John Ericson <John.Ericson at Obsidian.Systems>
Date: Sun, 30 Jun 2024 18:47:58 -0400
Subject: [PATCH 4/4] [LLD] Scope OpenBSD special section handling under that
 ELFOSABI

As the preexisting comment (that I referred to) says:

> section names shouldn't be significant in ELF in spirit.

so scoping OSABI-specific magic name hacks to just the OSABI in question
limits the degree to which we deviate from that "spirit" for all other
OSABIs.

OpenBSD in particular is very fast moving, having added a number of
special sections, etc. in recent years. It is unclear how possible /
reasonable it is for upstream to implement all these features in any
event, but scoping like this at least mitigates the fallout for other
OSABIs systems which wish to be more slow-moving.
---
 lld/ELF/Writer.cpp | 49 ++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index efa9383e70726..ba0df2042964f 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -601,10 +601,16 @@ static bool isRelroSection(const OutputSection *sec) {
   // ELF in spirit. But in reality many linker features depend on
   // magic section names.
   StringRef s = sec->name;
-  return s == ".data.rel.ro" || s == ".bss.rel.ro" || s == ".ctors" ||
-         s == ".dtors" || s == ".jcr" || s == ".eh_frame" ||
-         s == ".fini_array" || s == ".init_array" ||
-         s == ".openbsd.randomdata" || s == ".preinit_array";
+
+  bool abiAgnostic = s == ".data.rel.ro" || s == ".bss.rel.ro" ||
+                     s == ".ctors" || s == ".dtors" || s == ".jcr" ||
+                     s == ".eh_frame" || s == ".fini_array" ||
+                     s == ".init_array" || s == ".preinit_array";
+
+  bool abiSpecific =
+      config->osabi == ELFOSABI_OPENBSD && s == ".openbsd.randomdata";
+
+  return abiAgnostic || abiSpecific;
 }
 
 // We compute a rank for each section. The rank indicates where the
@@ -2273,21 +2279,26 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
     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);
+  // Handle OpenBSD-specific section types for OpenBSD "OS ABI".
+  //
+  // Scoped to just this "OS ABI" because, as is written below "section
+  // names shouldn't be significant in ELF in spirit".
+  if (config->osabi == ELFOSABI_OPENBSD) {
+    // PT_OPENBSD_MUTABLE 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 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 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



More information about the llvm-commits mailing list