Commit 4e45362529

mlugg <mlugg@mlugg.co.uk>
2025-09-10 17:41:10
link.Elf: fix static PIE
We mustn't emit the DT_PLTGOT entry in `.dynamic` in a statically-linked PIE, because there's no dl to relocate it (and `std.pie.relocate`, or the PIE relocator in libc, won't touch it). In that case, there cannot be any PLT entries, so there's no point emitting the `.got.plt` section at all. If we just don't create that section, `link.Elf` already knows not to add the DT_PLTGOT entry to `.dynamic`. Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com>
1 parent 1123741
Changed files (2)
lib/std/dynamic_library.zig
@@ -95,8 +95,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
 pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
     _ = phdrs;
     const _DYNAMIC = get_DYNAMIC() orelse {
-        // No PT_DYNAMIC means this is either a statically-linked program or a
-        // badly corrupted dynamically-linked one.
+        // No PT_DYNAMIC means this is a statically-linked non-PIE program.
         return .{ .current = null };
     };
 
src/link/Elf.zig
@@ -1884,6 +1884,16 @@ fn initSyntheticSections(self: *Elf) !void {
     const ptr_size = self.ptrWidthBytes();
     const shared_objects = self.shared_objects.values();
 
+    const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
+        .Exe => true,
+        .Lib => comp.config.link_mode == .dynamic,
+        .Obj => false,
+    };
+    const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
+
+    const needs_interp = have_dynamic_linker and
+        (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
+
     const needs_eh_frame = blk: {
         if (self.zigObjectPtr()) |zo|
             if (zo.eh_frame_index != null) break :blk true;
@@ -1891,6 +1901,7 @@ fn initSyntheticSections(self: *Elf) !void {
             if (self.file(index).?.object.cies.items.len > 0) break true;
         } else false;
     };
+
     if (needs_eh_frame) {
         if (self.section_indexes.eh_frame == null) {
             self.section_indexes.eh_frame = self.sectionByName(".eh_frame") orelse try self.addSection(.{
@@ -1922,13 +1933,17 @@ fn initSyntheticSections(self: *Elf) !void {
         });
     }
 
-    if (self.section_indexes.got_plt == null) {
-        self.section_indexes.got_plt = try self.addSection(.{
-            .name = try self.insertShString(".got.plt"),
-            .type = elf.SHT_PROGBITS,
-            .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
-            .addralign = @alignOf(u64),
-        });
+    if (have_dynamic_linker) {
+        if (self.section_indexes.got_plt == null) {
+            self.section_indexes.got_plt = try self.addSection(.{
+                .name = try self.insertShString(".got.plt"),
+                .type = elf.SHT_PROGBITS,
+                .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
+                .addralign = @alignOf(u64),
+            });
+        }
+    } else {
+        assert(self.plt.symbols.items.len == 0);
     }
 
     const needs_rela_dyn = blk: {
@@ -1989,16 +2004,6 @@ fn initSyntheticSections(self: *Elf) !void {
         });
     }
 
-    const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
-        .Exe => true,
-        .Lib => comp.config.link_mode == .dynamic,
-        .Obj => false,
-    };
-    const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
-
-    const needs_interp = have_dynamic_linker and
-        (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
-
     if (needs_interp and self.section_indexes.interp == null) {
         self.section_indexes.interp = try self.addSection(.{
             .name = try self.insertShString(".interp"),