Commit 96d3c4f54f

Jakub Konka <kubkon@jakubkonka.com>
2021-06-14 12:56:53
zld: clean up parsing section by type and attrs
1 parent 6fad1d4
Changed files (2)
src
src/link/MachO/Object.zig
@@ -70,6 +70,43 @@ pub const Section = struct {
             allocator.free(relocs);
         }
     }
+
+    pub fn segname(self: Section) []const u8 {
+        return parseName(&self.inner.segname);
+    }
+
+    pub fn sectname(self: Section) []const u8 {
+        return parseName(&self.inner.sectname);
+    }
+
+    pub fn flags(self: Section) u32 {
+        return self.inner.flags;
+    }
+
+    pub fn sectionType(self: Section) u8 {
+        return @truncate(u8, self.flags() & 0xff);
+    }
+
+    pub fn sectionAttrs(self: Section) u32 {
+        return self.flags() & 0xffffff00;
+    }
+
+    pub fn isCode(self: Section) bool {
+        const attr = self.sectionAttrs();
+        return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 and attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0;
+    }
+
+    pub fn isDebug(self: Section) bool {
+        return self.sectionAttrs() & macho.S_ATTR_DEBUG != 0;
+    }
+
+    pub fn dontDeadStrip(self: Section) bool {
+        return self.sectionAttrs() & macho.S_ATTR_NO_DEAD_STRIP != 0;
+    }
+
+    pub fn dontDeadStripIfReferencesLive(self: Section) bool {
+        return self.sectionAttrs() & macho.S_ATTR_LIVE_SUPPORT != 0;
+    }
 };
 
 const DebugInfo = struct {
src/link/MachO/Zld.zig
@@ -409,7 +409,7 @@ fn mapAndUpdateSections(
     const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);
     const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment);
 
-    log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
+    log.warn("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
         object.name.?,
         parseName(&source_sect.inner.segname),
         parseName(&source_sect.inner.sectname),
@@ -435,19 +435,17 @@ fn updateMetadata(self: *Zld) !void {
         const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
 
         // Create missing metadata
-        for (object_seg.sections.items) |source_sect, sect_id| {
-            if (sect_id == object.text_section_index.?) continue;
-            const segname = parseName(&source_sect.segname);
-            const sectname = parseName(&source_sect.sectname);
-            const flags = source_sect.flags;
+        for (object.sections.items) |sect, sect_id| {
+            const segname = sect.segname();
+            const sectname = sect.sectname();
 
-            switch (flags) {
-                macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS => {
-                    if (self.text_section_index != null) continue;
+            switch (sect.sectionType()) {
+                macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => {
+                    if (self.text_const_section_index != null) continue;
 
-                    self.text_section_index = @intCast(u16, text_seg.sections.items.len);
+                    self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
                     try text_seg.addSection(self.allocator, .{
-                        .sectname = makeStaticString("__text"),
+                        .sectname = makeStaticString("__const"),
                         .segname = makeStaticString("__TEXT"),
                         .addr = 0,
                         .size = 0,
@@ -455,70 +453,12 @@ fn updateMetadata(self: *Zld) !void {
                         .@"align" = 0,
                         .reloff = 0,
                         .nreloc = 0,
-                        .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+                        .flags = macho.S_REGULAR,
                         .reserved1 = 0,
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
-                },
-                macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
-                    if (mem.eql(u8, segname, "__TEXT")) {
-                        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") or mem.eql(u8, segname, "__DATA_CONST")) {
-                        if (self.data_const_section_index != null) continue;
-
-                        self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
-                        try data_const_seg.addSection(self.allocator, .{
-                            .sectname = makeStaticString("__const"),
-                            .segname = makeStaticString("__DATA_CONST"),
-                            .addr = 0,
-                            .size = 0,
-                            .offset = 0,
-                            .@"align" = 0,
-                            .reloff = 0,
-                            .nreloc = 0,
-                            .flags = macho.S_REGULAR,
-                            .reserved1 = 0,
-                            .reserved2 = 0,
-                            .reserved3 = 0,
-                        });
-                    }
+                    continue;
                 },
                 macho.S_CSTRING_LITERALS => {
                     if (self.cstring_section_index != null) continue;
@@ -538,6 +478,7 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
+                    continue;
                 },
                 macho.S_MOD_INIT_FUNC_POINTERS => {
                     if (self.mod_init_func_section_index != null) continue;
@@ -557,6 +498,7 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
+                    continue;
                 },
                 macho.S_MOD_TERM_FUNC_POINTERS => {
                     if (self.mod_term_func_section_index != null) continue;
@@ -576,6 +518,7 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
+                    continue;
                 },
                 macho.S_ZEROFILL => {
                     if (mem.eql(u8, sectname, "__common")) {
@@ -615,6 +558,7 @@ fn updateMetadata(self: *Zld) !void {
                             .reserved3 = 0,
                         });
                     }
+                    continue;
                 },
                 macho.S_THREAD_LOCAL_VARIABLES => {
                     if (self.tlv_section_index != null) continue;
@@ -634,6 +578,7 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
+                    continue;
                 },
                 macho.S_THREAD_LOCAL_REGULAR => {
                     if (self.tlv_data_section_index != null) continue;
@@ -653,6 +598,7 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
+                    continue;
                 },
                 macho.S_THREAD_LOCAL_ZEROFILL => {
                     if (self.tlv_bss_section_index != null) continue;
@@ -672,58 +618,185 @@ fn updateMetadata(self: *Zld) !void {
                         .reserved2 = 0,
                         .reserved3 = 0,
                     });
-                },
-                macho.S_COALESCED |
-                    macho.S_ATTR_NO_TOC |
-                    macho.S_ATTR_STRIP_STATIC_SYMS |
-                    macho.S_ATTR_LIVE_SUPPORT => {
-                    log.debug("TODO __eh_frame section: type 0x{x}, name '{s},{s}'", .{
-                        flags, segname, sectname,
-                    });
                     continue;
                 },
-                macho.S_REGULAR | macho.S_ATTR_DEBUG => {
-                    if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
-                        log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
-                            flags, segname, sectname,
+                macho.S_COALESCED => {
+                    if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {
+                        log.debug("TODO __eh_frame section: type 0x{x}, name '{s},{s}'", .{
+                            sect.flags(), segname, sectname,
                         });
+                        continue;
                     }
-                    continue;
                 },
-                else => {
+                macho.S_REGULAR => {
+                    if (sect.isCode()) {
+                        if (self.text_section_index != null) continue;
+
+                        self.text_section_index = @intCast(u16, text_seg.sections.items.len);
+                        try text_seg.addSection(self.allocator, .{
+                            .sectname = makeStaticString("__text"),
+                            .segname = makeStaticString("__TEXT"),
+                            .addr = 0,
+                            .size = 0,
+                            .offset = 0,
+                            .@"align" = 0,
+                            .reloff = 0,
+                            .nreloc = 0,
+                            .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+                            .reserved1 = 0,
+                            .reserved2 = 0,
+                            .reserved3 = 0,
+                        });
+                        continue;
+                    }
+                    if (sect.isDebug()) {
+                        if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
+                            log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
+                                sect.flags(), segname, sectname,
+                            });
+                        }
+                        continue;
+                    }
+
+                    if (mem.eql(u8, segname, "__TEXT")) {
+                        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,
+                            });
+                        }
+                        continue;
+                    }
+
+                    if (mem.eql(u8, segname, "__DATA_CONST")) {
+                        if (self.data_const_section_index != null) continue;
+
+                        self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
+                        try data_const_seg.addSection(self.allocator, .{
+                            .sectname = makeStaticString("__const"),
+                            .segname = makeStaticString("__DATA_CONST"),
+                            .addr = 0,
+                            .size = 0,
+                            .offset = 0,
+                            .@"align" = 0,
+                            .reloff = 0,
+                            .nreloc = 0,
+                            .flags = macho.S_REGULAR,
+                            .reserved1 = 0,
+                            .reserved2 = 0,
+                            .reserved3 = 0,
+                        });
+                        continue;
+                    }
+
+                    if (mem.eql(u8, segname, "__DATA")) {
+                        if (mem.eql(u8, sectname, "__const")) {
+                            if (self.data_const_section_index != null) continue;
+
+                            self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
+                            try data_const_seg.addSection(self.allocator, .{
+                                .sectname = makeStaticString("__const"),
+                                .segname = makeStaticString("__DATA_CONST"),
+                                .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.data_section_index != null) continue;
+
+                            self.data_section_index = @intCast(u16, data_seg.sections.items.len);
+                            try data_seg.addSection(self.allocator, .{
+                                .sectname = makeStaticString("__data"),
+                                .segname = makeStaticString("__DATA"),
+                                .addr = 0,
+                                .size = 0,
+                                .offset = 0,
+                                .@"align" = 0,
+                                .reloff = 0,
+                                .nreloc = 0,
+                                .flags = macho.S_REGULAR,
+                                .reserved1 = 0,
+                                .reserved2 = 0,
+                                .reserved3 = 0,
+                            });
+                        }
+
+                        continue;
+                    }
+
                     if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) {
-                        log.debug("TODO LLVM bitcode section: type 0x{x}, name '{s},{s}'", .{
-                            flags, segname, sectname,
+                        log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{
+                            sect.flags(), segname, sectname,
                         });
                         continue;
                     }
-                    log.err("unhandled section type 0x{x} for '{s},{s}'", .{ flags, segname, sectname });
-                    return error.UnhandledSection;
                 },
+                else => {},
             }
+
+            log.err("{s}: unhandled section type 0x{x} for '{s},{s}'", .{
+                object.name.?,
+                sect.flags(),
+                segname,
+                sectname,
+            });
+            return error.UnhandledSection;
         }
 
         // Find ideal section alignment.
-        for (object_seg.sections.items) |source_sect| {
-            if (self.getMatchingSection(source_sect)) |res| {
+        for (object.sections.items) |sect| {
+            if (self.getMatchingSection(sect)) |res| {
                 const target_seg = &self.load_commands.items[res.seg].Segment;
                 const target_sect = &target_seg.sections.items[res.sect];
-                target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align");
+                target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align");
             }
         }
 
         // Update section mappings
-        for (object_seg.sections.items) |source_sect, sect_id| {
-            const source_sect_id = @intCast(u16, sect_id);
-            if (self.getMatchingSection(source_sect)) |res| {
-                try self.mapAndUpdateSections(object, source_sect_id, res.seg, res.sect);
+        for (object.sections.items) |sect, sect_id| {
+            if (self.getMatchingSection(sect)) |res| {
+                try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect);
                 continue;
             }
-
-            log.debug("section '{s},{s}' will be unmapped", .{
-                parseName(&source_sect.segname),
-                parseName(&source_sect.sectname),
-            });
+            log.warn("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() });
         }
     }
 
@@ -819,13 +892,13 @@ const MatchingSection = struct {
     sect: u16,
 };
 
-fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
-    const segname = parseName(&section.segname);
-    const sectname = parseName(&section.sectname);
+fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
+    const segname = sect.segname();
+    const sectname = sect.sectname();
 
     const res: ?MatchingSection = blk: {
-        switch (section.flags) {
-            macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
+        switch (sect.sectionType()) {
+            macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => {
                 break :blk .{
                     .seg = self.text_segment_cmd_index.?,
                     .sect = self.text_const_section_index.?,
@@ -855,11 +928,12 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
                         .seg = self.data_segment_cmd_index.?,
                         .sect = self.common_section_index.?,
                     };
+                } else {
+                    break :blk .{
+                        .seg = self.data_segment_cmd_index.?,
+                        .sect = self.bss_section_index.?,
+                    };
                 }
-                break :blk .{
-                    .seg = self.data_segment_cmd_index.?,
-                    .sect = self.bss_section_index.?,
-                };
             },
             macho.S_THREAD_LOCAL_VARIABLES => {
                 break :blk .{
@@ -879,31 +953,43 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
                     .sect = self.tlv_bss_section_index.?,
                 };
             },
-            macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS => {
-                break :blk .{
-                    .seg = self.text_segment_cmd_index.?,
-                    .sect = self.text_section_index.?,
-                };
+            macho.S_COALESCED => {
+                // TODO coalesced sections
+                break :blk null;
             },
             macho.S_REGULAR => {
+                if (sect.isCode()) {
+                    break :blk .{
+                        .seg = self.text_segment_cmd_index.?,
+                        .sect = self.text_section_index.?,
+                    };
+                }
+                if (sect.isDebug()) {
+                    // TODO debug attributes
+                    break :blk null;
+                }
+
                 if (mem.eql(u8, segname, "__TEXT")) {
                     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.?,
+                        };
                     }
-                    break :blk .{
-                        .seg = self.text_segment_cmd_index.?,
-                        .sect = self.text_const_section_index.?,
-                    };
                 }
+
                 if (mem.eql(u8, segname, "__DATA_CONST")) {
                     break :blk .{
                         .seg = self.data_const_segment_cmd_index.?,
                         .sect = self.data_const_section_index.?,
                     };
                 }
+
                 if (mem.eql(u8, segname, "__DATA")) {
                     if (mem.eql(u8, sectname, "__const")) {
                         break :blk .{
@@ -916,11 +1002,10 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
                         .sect = self.data_section_index.?,
                     };
                 }
+
                 break :blk null;
             },
-            else => {
-                break :blk null;
-            },
+            else => break :blk null,
         }
     };