From a1b607acb5c1e9dd03760efd7078185e7628b29d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 4 Feb 2024 11:23:17 +0100 Subject: [PATCH] macho: sanitize Zig sections segment names before emitting a relocatable As reported by jacobly, the Apple system linker matches sections to segments by name and not by flags causing Zig's executable section ending up in a segment with incorrect permission flags. --- src/link/MachO/relocatable.zig | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index a69423b333..5e9eb9f823 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -78,6 +78,10 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u off = mem.alignForward(u32, off, @alignOf(u64)); off = try macho_file.writeStrtab(off); + // In order to please Apple ld (and possibly other MachO linkers in the wild), + // we will now sanitize segment names of Zig-specific segments. + sanitizeZigSections(macho_file); + const ncmds, const sizeofcmds = try writeLoadCommands(macho_file); try writeHeader(macho_file, ncmds, sizeofcmds); } @@ -245,6 +249,31 @@ fn allocateSections(macho_file: *MachO) !void { } } +/// Renames segment names in Zig sections to standard MachO segment names such as +/// `__TEXT`, `__DATA_CONST` and `__DATA`. +/// TODO: I think I may be able to get rid of this if I rework section/segment +/// allocation mechanism to not rely so much on having `_ZIG` sections always +/// pushed to the back. For instance, this is not a problem in ELF linker. +/// Then, we can create sections with the correct name from the start in `MachO.initMetadata`. +fn sanitizeZigSections(macho_file: *MachO) void { + if (macho_file.zig_text_sect_index) |index| { + const header = &macho_file.sections.items(.header)[index]; + header.segname = MachO.makeStaticString("__TEXT"); + } + if (macho_file.zig_const_sect_index) |index| { + const header = &macho_file.sections.items(.header)[index]; + header.segname = MachO.makeStaticString("__DATA_CONST"); + } + if (macho_file.zig_data_sect_index) |index| { + const header = &macho_file.sections.items(.header)[index]; + header.segname = MachO.makeStaticString("__DATA"); + } + if (macho_file.zig_bss_sect_index) |index| { + const header = &macho_file.sections.items(.header)[index]; + header.segname = MachO.makeStaticString("__DATA"); + } +} + fn createSegment(macho_file: *MachO) !void { const gpa = macho_file.base.comp.gpa;