Commit 96556ce8b8

Jakub Konka <kubkon@jakubkonka.com>
2021-05-04 10:59:33
zld: port over a few more bits from ld64
* UTF16 gets its own section, `__TEXT,__ustring` * TLV data and bss sections have to aligned to the same max alignment according to Apple rdar comment in the latest ld64
1 parent 1867c3c
Changed files (1)
src
link
MachO
src/link/MachO/Zld.zig
@@ -58,6 +58,7 @@ stubs_section_index: ?u16 = null,
 stub_helper_section_index: ?u16 = null,
 text_const_section_index: ?u16 = null,
 cstring_section_index: ?u16 = null,
+ustring_section_index: ?u16 = null,
 
 // __DATA_CONST segment sections
 got_section_index: ?u16 = null,
@@ -200,7 +201,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
     try self.populateMetadata();
     try self.parseInputFiles(files);
     try self.resolveSymbols();
-    // self.printSymbols();
     try self.resolveStubsAndGotEntries();
     try self.updateMetadata();
     try self.sortSections();
@@ -209,8 +209,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
     try self.allocateDataSegment();
     self.allocateLinkeditSegment();
     try self.allocateSymbols();
-    try self.writeStubHelperCommon();
-    try self.resolveRelocsAndWriteSections();
     try self.flush();
 }
 
@@ -356,23 +354,43 @@ fn updateMetadata(self: *Zld) !void {
             switch (flags) {
                 macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
                     if (mem.eql(u8, segname, "__TEXT")) {
-                        if (self.text_const_section_index != null) continue;
-
-                        self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
-                        try text_seg.addSection(self.allocator, .{
-                            .sectname = makeStaticString("__const"),
-                            .segname = makeStaticString("__TEXT"),
-                            .addr = 0,
-                            .size = 0,
-                            .offset = 0,
-                            .@"align" = 0,
-                            .reloff = 0,
-                            .nreloc = 0,
-                            .flags = macho.S_REGULAR,
-                            .reserved1 = 0,
-                            .reserved2 = 0,
-                            .reserved3 = 0,
-                        });
+                        if (mem.eql(u8, sectname, "__ustring")) {
+                            if (self.ustring_section_index != null) continue;
+
+                            self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);
+                            try text_seg.addSection(self.allocator, .{
+                                .sectname = makeStaticString("__ustring"),
+                                .segname = makeStaticString("__TEXT"),
+                                .addr = 0,
+                                .size = 0,
+                                .offset = 0,
+                                .@"align" = 0,
+                                .reloff = 0,
+                                .nreloc = 0,
+                                .flags = macho.S_REGULAR,
+                                .reserved1 = 0,
+                                .reserved2 = 0,
+                                .reserved3 = 0,
+                            });
+                        } else {
+                            if (self.text_const_section_index != null) continue;
+
+                            self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
+                            try text_seg.addSection(self.allocator, .{
+                                .sectname = makeStaticString("__const"),
+                                .segname = makeStaticString("__TEXT"),
+                                .addr = 0,
+                                .size = 0,
+                                .offset = 0,
+                                .@"align" = 0,
+                                .reloff = 0,
+                                .nreloc = 0,
+                                .flags = macho.S_REGULAR,
+                                .reserved1 = 0,
+                                .reserved2 = 0,
+                                .reserved3 = 0,
+                            });
+                        }
                     } else if (mem.eql(u8, segname, "__DATA")) {
                         if (!mem.eql(u8, sectname, "__const")) continue;
                         if (self.data_const_section_index != null) continue;
@@ -588,6 +606,50 @@ fn updateMetadata(self: *Zld) !void {
             }, 0);
         }
     }
+
+    tlv_align: {
+        const has_tlv =
+            self.tlv_section_index != null or
+            self.tlv_data_section_index != null or
+            self.tlv_bss_section_index != null;
+
+        if (!has_tlv) break :tlv_align;
+
+        const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+
+        if (self.tlv_section_index) |index| {
+            const sect = &seg.sections.items[index];
+            sect.@"align" = 3; // __thread_vars is always 8byte aligned
+        }
+
+        // Apparently __tlv_data and __tlv_bss need to have matching alignment, so fix it up.
+        // <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
+        // https://github.com/apple-opensource/ld64/blob/e28c028b20af187a16a7161d89e91868a450cadc/src/ld/ld.cpp#L1172
+        const data_align: u32 = data: {
+            if (self.tlv_data_section_index) |index| {
+                const sect = &seg.sections.items[index];
+                break :data sect.@"align";
+            }
+            break :tlv_align;
+        };
+        const bss_align: u32 = bss: {
+            if (self.tlv_bss_section_index) |index| {
+                const sect = &seg.sections.items[index];
+                break :bss sect.@"align";
+            }
+            break :tlv_align;
+        };
+        const max_align = math.max(data_align, bss_align);
+
+        if (self.tlv_data_section_index) |index| {
+            const sect = &seg.sections.items[index];
+            sect.@"align" = max_align;
+        }
+        if (self.tlv_bss_section_index) |index| {
+            const sect = &seg.sections.items[index];
+            sect.@"align" = max_align;
+        }
+    }
 }
 
 const MatchingSection = struct {
@@ -663,10 +725,17 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
             },
             macho.S_REGULAR => {
                 if (mem.eql(u8, segname, "__TEXT")) {
-                    break :blk .{
-                        .seg = self.text_segment_cmd_index.?,
-                        .sect = self.text_const_section_index.?,
-                    };
+                    if (mem.eql(u8, sectname, "__ustring")) {
+                        break :blk .{
+                            .seg = self.text_segment_cmd_index.?,
+                            .sect = self.ustring_section_index.?,
+                        };
+                    } else {
+                        break :blk .{
+                            .seg = self.text_segment_cmd_index.?,
+                            .sect = self.text_const_section_index.?,
+                        };
+                    }
                 } else if (mem.eql(u8, segname, "__DATA")) {
                     if (mem.eql(u8, sectname, "__data")) {
                         break :blk .{
@@ -712,6 +781,7 @@ fn sortSections(self: *Zld) !void {
             &self.stub_helper_section_index,
             &self.text_const_section_index,
             &self.cstring_section_index,
+            &self.ustring_section_index,
         };
         for (indices) |maybe_index| {
             const new_index: u16 = if (maybe_index.*) |index| blk: {
@@ -1991,6 +2061,9 @@ fn populateMetadata(self: *Zld) !void {
 }
 
 fn flush(self: *Zld) !void {
+    try self.writeStubHelperCommon();
+    try self.resolveRelocsAndWriteSections();
+
     if (self.common_section_index) |index| {
         const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
         const sect = &seg.sections.items[index];