diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 4095a1c333..eb5e76462f 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -1,23 +1,3 @@ -const Atom = @This(); - -const std = @import("std"); -const build_options = @import("build_options"); -const aarch64 = @import("../../arch/aarch64/bits.zig"); -const assert = std.debug.assert; -const log = std.log.scoped(.link); -const macho = std.macho; -const math = std.math; -const mem = std.mem; -const meta = std.meta; -const trace = @import("../../tracy.zig").trace; - -const Allocator = mem.Allocator; -const Arch = std.Target.Cpu.Arch; -const MachO = @import("../MachO.zig"); -pub const Relocation = @import("Relocation.zig"); -const SymbolWithLoc = MachO.SymbolWithLoc; -const Zld = @import("zld.zig").Zld; - /// Each Atom always gets a symbol with the fully qualified name. /// The symbol can reside in any object file context structure in `symtab` array /// (see `Object`), or if the symbol is a synthetic symbol such as a GOT cell or @@ -125,6 +105,144 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { return surplus >= MachO.min_text_capacity; } +pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 { + const segname = sect.segName(); + const sectname = sect.sectName(); + const res: ?u8 = blk: { + if (mem.eql(u8, "__LLVM", segname)) { + log.debug("TODO LLVM section: type 0x{x}, name '{s},{s}'", .{ + sect.flags, segname, sectname, + }); + break :blk null; + } + + // We handle unwind info separately. + if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) { + break :blk null; + } + if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { + break :blk null; + } + + if (sect.isCode()) { + if (zld.text_section_index == null) { + zld.text_section_index = try zld.initSection( + "__TEXT", + "__text", + .{ + .flags = macho.S_REGULAR | + macho.S_ATTR_PURE_INSTRUCTIONS | + macho.S_ATTR_SOME_INSTRUCTIONS, + }, + ); + } + break :blk zld.text_section_index.?; + } + + if (sect.isDebug()) { + break :blk null; + } + + switch (sect.type()) { + macho.S_4BYTE_LITERALS, + macho.S_8BYTE_LITERALS, + macho.S_16BYTE_LITERALS, + => { + break :blk zld.getSectionByName("__TEXT", "__const") orelse try zld.initSection( + "__TEXT", + "__const", + .{}, + ); + }, + macho.S_CSTRING_LITERALS => { + if (mem.startsWith(u8, sectname, "__objc")) { + break :blk zld.getSectionByName(segname, sectname) orelse try zld.initSection( + segname, + sectname, + .{}, + ); + } + break :blk zld.getSectionByName("__TEXT", "__cstring") orelse try zld.initSection( + "__TEXT", + "__cstring", + .{ .flags = macho.S_CSTRING_LITERALS }, + ); + }, + macho.S_MOD_INIT_FUNC_POINTERS, + macho.S_MOD_TERM_FUNC_POINTERS, + => { + break :blk zld.getSectionByName("__DATA_CONST", sectname) orelse try zld.initSection( + "__DATA_CONST", + sectname, + .{ .flags = sect.flags }, + ); + }, + macho.S_LITERAL_POINTERS, + macho.S_ZEROFILL, + macho.S_THREAD_LOCAL_VARIABLES, + macho.S_THREAD_LOCAL_VARIABLE_POINTERS, + macho.S_THREAD_LOCAL_REGULAR, + macho.S_THREAD_LOCAL_ZEROFILL, + => { + break :blk zld.getSectionByName(segname, sectname) orelse try zld.initSection( + segname, + sectname, + .{ .flags = sect.flags }, + ); + }, + macho.S_COALESCED => { + break :blk zld.getSectionByName(segname, sectname) orelse try zld.initSection( + segname, + sectname, + .{}, + ); + }, + macho.S_REGULAR => { + if (mem.eql(u8, segname, "__TEXT")) { + if (mem.eql(u8, sectname, "__rodata") or + mem.eql(u8, sectname, "__typelink") or + mem.eql(u8, sectname, "__itablink") or + mem.eql(u8, sectname, "__gosymtab") or + mem.eql(u8, sectname, "__gopclntab")) + { + break :blk zld.getSectionByName("__TEXT", sectname) orelse try zld.initSection( + "__TEXT", + sectname, + .{}, + ); + } + } + if (mem.eql(u8, segname, "__DATA")) { + if (mem.eql(u8, sectname, "__const") or + mem.eql(u8, sectname, "__cfstring") or + mem.eql(u8, sectname, "__objc_classlist") or + mem.eql(u8, sectname, "__objc_imageinfo")) + { + break :blk zld.getSectionByName("__DATA_CONST", sectname) orelse try zld.initSection( + "__DATA_CONST", + sectname, + .{}, + ); + } else if (mem.eql(u8, sectname, "__data")) { + break :blk zld.getSectionByName("__DATA", "__data") orelse try zld.initSection( + "__DATA", + "__data", + .{}, + ); + } + } + break :blk zld.getSectionByName(segname, sectname) orelse try zld.initSection( + segname, + sectname, + .{}, + ); + }, + else => break :blk null, + } + }; + return res; +} + pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void { return addRelocations(macho_file, atom_index, &[_]Relocation{reloc}); } @@ -1112,3 +1230,23 @@ pub fn relocIsStub(zld: *Zld, rel: macho.relocation_info) bool { else => unreachable, } } + +const Atom = @This(); + +const std = @import("std"); +const build_options = @import("build_options"); +const aarch64 = @import("../../arch/aarch64/bits.zig"); +const assert = std.debug.assert; +const log = std.log.scoped(.link); +const macho = std.macho; +const math = std.math; +const mem = std.mem; +const meta = std.meta; +const trace = @import("../../tracy.zig").trace; + +const Allocator = mem.Allocator; +const Arch = std.Target.Cpu.Arch; +const MachO = @import("../MachO.zig"); +pub const Relocation = @import("Relocation.zig"); +const SymbolWithLoc = MachO.SymbolWithLoc; +const Zld = @import("zld.zig").Zld; diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 8c523779ea..c9f32aa4fd 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -377,7 +377,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { const sections = self.getSourceSections(); for (sections, 0..) |sect, id| { if (sect.isDebug()) continue; - const out_sect_id = (try zld.getOutputSection(sect)) orelse { + const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse { log.debug(" unhandled section '{s},{s}'", .{ sect.segName(), sect.sectName() }); continue; }; @@ -397,7 +397,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { if (self.in_symtab == null) { for (sections, 0..) |sect, id| { if (sect.isDebug()) continue; - const out_sect_id = (try zld.getOutputSection(sect)) orelse continue; + const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse continue; if (sect.size == 0) continue; const sect_id = @as(u8, @intCast(id)); @@ -456,7 +456,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() }); // Get output segment/section in the final artifact. - const out_sect_id = (try zld.getOutputSection(sect)) orelse continue; + const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse continue; log.debug(" output sect({d}, '{s},{s}')", .{ out_sect_id + 1, diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 7fa506ce0e..d4dd599d2d 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -95,144 +95,6 @@ pub const Zld = struct { atoms: std.ArrayListUnmanaged(Atom) = .{}, - pub fn getOutputSection(self: *Zld, sect: macho.section_64) !?u8 { - const segname = sect.segName(); - const sectname = sect.sectName(); - const res: ?u8 = blk: { - if (mem.eql(u8, "__LLVM", segname)) { - log.debug("TODO LLVM section: type 0x{x}, name '{s},{s}'", .{ - sect.flags, segname, sectname, - }); - break :blk null; - } - - // We handle unwind info separately. - if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) { - break :blk null; - } - if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { - break :blk null; - } - - if (sect.isCode()) { - if (self.text_section_index == null) { - self.text_section_index = try self.initSection( - "__TEXT", - "__text", - .{ - .flags = macho.S_REGULAR | - macho.S_ATTR_PURE_INSTRUCTIONS | - macho.S_ATTR_SOME_INSTRUCTIONS, - }, - ); - } - break :blk self.text_section_index.?; - } - - if (sect.isDebug()) { - break :blk null; - } - - switch (sect.type()) { - macho.S_4BYTE_LITERALS, - macho.S_8BYTE_LITERALS, - macho.S_16BYTE_LITERALS, - => { - break :blk self.getSectionByName("__TEXT", "__const") orelse try self.initSection( - "__TEXT", - "__const", - .{}, - ); - }, - macho.S_CSTRING_LITERALS => { - if (mem.startsWith(u8, sectname, "__objc")) { - break :blk self.getSectionByName(segname, sectname) orelse try self.initSection( - segname, - sectname, - .{}, - ); - } - break :blk self.getSectionByName("__TEXT", "__cstring") orelse try self.initSection( - "__TEXT", - "__cstring", - .{ .flags = macho.S_CSTRING_LITERALS }, - ); - }, - macho.S_MOD_INIT_FUNC_POINTERS, - macho.S_MOD_TERM_FUNC_POINTERS, - => { - break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection( - "__DATA_CONST", - sectname, - .{ .flags = sect.flags }, - ); - }, - macho.S_LITERAL_POINTERS, - macho.S_ZEROFILL, - macho.S_THREAD_LOCAL_VARIABLES, - macho.S_THREAD_LOCAL_VARIABLE_POINTERS, - macho.S_THREAD_LOCAL_REGULAR, - macho.S_THREAD_LOCAL_ZEROFILL, - => { - break :blk self.getSectionByName(segname, sectname) orelse try self.initSection( - segname, - sectname, - .{ .flags = sect.flags }, - ); - }, - macho.S_COALESCED => { - break :blk self.getSectionByName(segname, sectname) orelse try self.initSection( - segname, - sectname, - .{}, - ); - }, - macho.S_REGULAR => { - if (mem.eql(u8, segname, "__TEXT")) { - if (mem.eql(u8, sectname, "__rodata") or - mem.eql(u8, sectname, "__typelink") or - mem.eql(u8, sectname, "__itablink") or - mem.eql(u8, sectname, "__gosymtab") or - mem.eql(u8, sectname, "__gopclntab")) - { - break :blk self.getSectionByName("__TEXT", sectname) orelse try self.initSection( - "__TEXT", - sectname, - .{}, - ); - } - } - if (mem.eql(u8, segname, "__DATA")) { - if (mem.eql(u8, sectname, "__const") or - mem.eql(u8, sectname, "__cfstring") or - mem.eql(u8, sectname, "__objc_classlist") or - mem.eql(u8, sectname, "__objc_imageinfo")) - { - break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection( - "__DATA_CONST", - sectname, - .{}, - ); - } else if (mem.eql(u8, sectname, "__data")) { - break :blk self.getSectionByName("__DATA", "__data") orelse try self.initSection( - "__DATA", - "__data", - .{}, - ); - } - } - break :blk self.getSectionByName(segname, sectname) orelse try self.initSection( - segname, - sectname, - .{}, - ); - }, - else => break :blk null, - } - }; - return res; - } - pub fn addAtomToSection(self: *Zld, atom_index: Atom.Index) void { const atom = self.getAtomPtr(atom_index); const sym = self.getSymbol(atom.getSymbolWithLoc()); @@ -278,7 +140,8 @@ pub const Zld = struct { const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); sym.n_type = macho.N_SECT; - const sect_id = self.getSectionByName("__DATA", "__data") orelse try self.initSection("__DATA", "__data", .{}); + const sect_id = self.getSectionByName("__DATA", "__data") orelse + try self.initSection("__DATA", "__data", .{}); sym.n_sect = sect_id + 1; self.dyld_private_atom_index = atom_index; @@ -301,16 +164,13 @@ pub const Zld = struct { // text blocks for each tentative definition. const size = sym.n_value; const alignment = (sym.n_desc >> 8) & 0x0f; - const n_sect = (try self.getOutputSection(.{ - .segname = makeStaticString("__DATA"), - .sectname = makeStaticString("__bss"), - .flags = macho.S_ZEROFILL, - })).? + 1; + const sect_id = self.getSectionByName("__DATA", "__bss") orelse + try self.initSection("__DATA", "__bss", .{ .flags = macho.S_ZEROFILL }); sym.* = .{ .n_strx = sym.n_strx, .n_type = macho.N_SECT | macho.N_EXT, - .n_sect = n_sect, + .n_sect = sect_id + 1, .n_desc = 0, .n_value = 0, };