zld+stage2: refactor creating segments and sections

Move the logic into default-init structs part of constructors in
`SegmentCommand` struct in `commands.zig` module.
This commit is contained in:
Jakub Konka 2021-06-21 11:11:19 +02:00
parent 72f2f68938
commit 852e1ed23c
5 changed files with 172 additions and 544 deletions

View File

@ -1779,18 +1779,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__PAGEZERO"),
.vmaddr = 0,
.Segment = SegmentCommand.empty("__PAGEZERO", .{
.vmsize = 0x100000000, // size always set to 4GB
.fileoff = 0,
.filesize = 0,
.maxprot = 0,
.initprot = 0,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -1809,18 +1799,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__TEXT"),
.Segment = SegmentCommand.empty("__TEXT", .{
.vmaddr = 0x100000000, // always starts at 4GB
.vmsize = needed_size,
.fileoff = 0,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -1841,19 +1825,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try text_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__text"),
.segname = makeStaticString("__TEXT"),
try text_segment.addSection(self.base.allocator, "__text", "__TEXT", .{
.addr = text_segment.inner.vmaddr + off,
.size = @intCast(u32, needed_size),
.offset = @intCast(u32, off),
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -1879,19 +1856,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try text_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__stubs"),
.segname = makeStaticString("__TEXT"),
try text_segment.addSection(self.base.allocator, "__stubs", "__TEXT", .{
.addr = text_segment.inner.vmaddr + off,
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = stub_size,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -1912,19 +1883,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try text_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__stub_helper"),
.segname = makeStaticString("__TEXT"),
try text_segment.addSection(self.base.allocator, "__stub_helper", "__TEXT", .{
.addr = text_segment.inner.vmaddr + off,
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -1941,18 +1905,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__DATA_CONST"),
.Segment = SegmentCommand.empty("__DATA_CONST", .{
.vmaddr = address_and_offset.address,
.vmsize = needed_size,
.fileoff = address_and_offset.offset,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -1969,19 +1928,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __got section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try dc_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__got"),
.segname = makeStaticString("__DATA_CONST"),
try dc_segment.addSection(self.base.allocator, "__got", "__DATA_CONST", .{
.addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff,
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -1998,18 +1950,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__DATA"),
.Segment = SegmentCommand.empty("__DATA", .{
.vmaddr = address_and_offset.address,
.vmsize = needed_size,
.fileoff = address_and_offset.offset,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -2026,19 +1973,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __la_symbol_ptr section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try data_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__la_symbol_ptr"),
.segname = makeStaticString("__DATA"),
try data_segment.addSection(self.base.allocator, "__la_symbol_ptr", "__DATA", .{
.addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -2047,26 +1987,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.data_section_index = @intCast(u16, data_segment.sections.items.len);
const flags = macho.S_REGULAR;
const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);
assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.
log.debug("found __data section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try data_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__data"),
.segname = makeStaticString("__DATA"),
try data_segment.addSection(self.base.allocator, "__data", "__DATA", .{
.addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = flags,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -2081,18 +2012,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__LINKEDIT"),
.Segment = SegmentCommand.empty("__LINKEDIT", .{
.vmaddr = address_and_offset.address,
.vmsize = 0,
.fileoff = address_and_offset.offset,
.filesize = 0,
.maxprot = maxprot,
.initprot = initprot,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -2450,13 +2374,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
return vaddr;
}
pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {
var buf = [_]u8{0} ** 16;
if (bytes.len > buf.len) @compileError("string too long; max 16 bytes");
mem.copy(u8, &buf, bytes);
return buf;
}
fn makeString(self: *MachO, bytes: []const u8) !u32 {
if (self.string_table_directory.get(bytes)) |offset| {
log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });

View File

@ -19,7 +19,6 @@ const MachO = @import("../MachO.zig");
const SrcFn = MachO.SrcFn;
const TextBlock = MachO.TextBlock;
const padToIdeal = MachO.padToIdeal;
const makeStaticString = MachO.makeStaticString;
usingnamespace @import("commands.zig");
@ -212,18 +211,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
log.debug("found dSym __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try self.load_commands.append(allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__DWARF"),
.Segment = SegmentCommand.empty("__DWARF", .{
.vmaddr = vmaddr,
.vmsize = needed_size,
.fileoff = off,
.filesize = needed_size,
.maxprot = 0,
.initprot = 0,
.nsects = 0,
.flags = 0,
}),
});
self.header_dirty = true;
@ -234,19 +226,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len);
assert(self.debug_string_table.items.len == 0);
try dwarf_segment.addSection(allocator, .{
.sectname = makeStaticString("__debug_str"),
.segname = makeStaticString("__DWARF"),
try dwarf_segment.addSection(allocator, "__debug_str", "__DWARF", .{
.addr = dwarf_segment.inner.vmaddr,
.size = @intCast(u32, self.debug_string_table.items.len),
.offset = @intCast(u32, dwarf_segment.inner.fileoff),
.@"align" = 1,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -262,19 +246,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
log.debug("found dSym __debug_info free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
try dwarf_segment.addSection(allocator, .{
.sectname = makeStaticString("__debug_info"),
.segname = makeStaticString("__DWARF"),
try dwarf_segment.addSection(allocator, "__debug_info", "__DWARF", .{
.addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
.size = file_size_hint,
.offset = @intCast(u32, off),
.@"align" = p_align,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -290,19 +266,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
log.debug("found dSym __debug_abbrev free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
try dwarf_segment.addSection(allocator, .{
.sectname = makeStaticString("__debug_abbrev"),
.segname = makeStaticString("__DWARF"),
try dwarf_segment.addSection(allocator, "__debug_abbrev", "__DWARF", .{
.addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
.size = file_size_hint,
.offset = @intCast(u32, off),
.@"align" = p_align,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -318,19 +286,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
log.debug("found dSym __debug_aranges free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
try dwarf_segment.addSection(allocator, .{
.sectname = makeStaticString("__debug_aranges"),
.segname = makeStaticString("__DWARF"),
try dwarf_segment.addSection(allocator, "__debug_aranges", "__DWARF", .{
.addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
.size = file_size_hint,
.offset = @intCast(u32, off),
.@"align" = p_align,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -346,19 +306,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
log.debug("found dSym __debug_line free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
try dwarf_segment.addSection(allocator, .{
.sectname = makeStaticString("__debug_line"),
.segname = makeStaticString("__DWARF"),
try dwarf_segment.addSection(allocator, "__debug_line", "__DWARF", .{
.addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
.size = file_size_hint,
.offset = @intCast(u32, off),
.@"align" = p_align,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
self.header_dirty = true;
self.load_commands_dirty = true;
@ -692,14 +644,10 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {
}
fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {
var cmd = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
var cmd = SegmentCommand.empty("", .{
.cmdsize = base_cmd.inner.cmdsize,
.segname = undefined,
.vmaddr = base_cmd.inner.vmaddr,
.vmsize = base_cmd.inner.vmsize,
.fileoff = 0,
.filesize = 0,
.maxprot = base_cmd.inner.maxprot,
.initprot = base_cmd.inner.initprot,
.nsects = base_cmd.inner.nsects,

View File

@ -60,7 +60,7 @@ pub fn parse(self: *Stub) !void {
const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
log.warn("parsing shared library from stub '{s}'", .{self.name.?});
log.debug("parsing shared library from stub '{s}'", .{self.name.?});
const umbrella_lib = lib_stub.inner[0];
self.id = .{
@ -93,14 +93,26 @@ pub fn parse(self: *Stub) !void {
if (exp.objc_classes) |classes| {
for (classes) |sym_name| {
log.warn(" | {s}", .{sym_name});
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_CLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
log.debug(" | {s}", .{sym_name});
{
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_CLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
}
{
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_METACLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
}
}
}
}
@ -118,16 +130,28 @@ pub fn parse(self: *Stub) !void {
}
if (stub.objc_classes) |classes| {
log.warn(" | objc_classes", .{});
log.debug(" | objc_classes", .{});
for (classes) |sym_name| {
log.warn(" | {s}", .{sym_name});
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_METACLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
log.debug(" | {s}", .{sym_name});
{
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_CLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
}
{
const actual_sym_name = try std.fmt.allocPrint(
self.allocator,
"_OBJC_METACLASS_$_{s}",
.{sym_name},
);
if (self.symbols.contains(actual_sym_name)) continue;
try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
}
}
}
}

View File

@ -79,6 +79,8 @@ mod_init_func_section_index: ?u16 = null,
mod_term_func_section_index: ?u16 = null,
data_const_section_index: ?u16 = null,
objc_cfstring_section_index: ?u16 = null,
// __DATA segment sections
tlv_section_index: ?u16 = null,
tlv_data_section_index: ?u16 = null,
@ -515,39 +517,15 @@ fn updateMetadata(self: *Zld) !void {
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,
});
try text_seg.addSection(self.allocator, "__const", "__TEXT", .{});
continue;
},
macho.S_CSTRING_LITERALS => {
if (self.cstring_section_index != null) continue;
self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__cstring"),
.segname = makeStaticString("__TEXT"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try text_seg.addSection(self.allocator, "__cstring", "__TEXT", .{
.flags = macho.S_CSTRING_LITERALS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -555,19 +533,8 @@ fn updateMetadata(self: *Zld) !void {
if (self.mod_init_func_section_index != null) continue;
self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__mod_init_func"),
.segname = makeStaticString("__DATA_CONST"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_const_seg.addSection(self.allocator, "__mod_init_func", "__DATA_CONST", .{
.flags = macho.S_MOD_INIT_FUNC_POINTERS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -575,19 +542,8 @@ fn updateMetadata(self: *Zld) !void {
if (self.mod_term_func_section_index != null) continue;
self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__mod_term_func"),
.segname = makeStaticString("__DATA_CONST"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_const_seg.addSection(self.allocator, "__mod_term_func", "__DATA_CONST", .{
.flags = macho.S_MOD_TERM_FUNC_POINTERS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -596,37 +552,15 @@ fn updateMetadata(self: *Zld) !void {
if (self.common_section_index != null) continue;
self.common_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__common"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__common", "__DATA", .{
.flags = macho.S_ZEROFILL,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
} else {
if (self.bss_section_index != null) continue;
self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__bss"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__bss", "__DATA", .{
.flags = macho.S_ZEROFILL,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
continue;
@ -635,19 +569,8 @@ fn updateMetadata(self: *Zld) !void {
if (self.tlv_section_index != null) continue;
self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__thread_vars"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__thread_vars", "__DATA", .{
.flags = macho.S_THREAD_LOCAL_VARIABLES,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -655,19 +578,8 @@ fn updateMetadata(self: *Zld) !void {
if (self.tlv_data_section_index != null) continue;
self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__thread_data"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__thread_data", "__DATA", .{
.flags = macho.S_THREAD_LOCAL_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -675,19 +587,8 @@ fn updateMetadata(self: *Zld) !void {
if (self.tlv_bss_section_index != null) continue;
self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__thread_bss"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__thread_bss", "__DATA", .{
.flags = macho.S_THREAD_LOCAL_ZEROFILL,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
},
@ -698,20 +599,7 @@ fn updateMetadata(self: *Zld) !void {
if (self.eh_frame_section_index != null) continue;
self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len);
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__eh_frame"),
.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,
});
try text_seg.addSection(self.allocator, "__eh_frame", "__TEXT", .{});
continue;
}
@ -719,20 +607,7 @@ fn updateMetadata(self: *Zld) !void {
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,
});
try data_const_seg.addSection(self.allocator, "__const", "__DATA_CONST", .{});
continue;
},
macho.S_REGULAR => {
@ -740,19 +615,8 @@ fn updateMetadata(self: *Zld) !void {
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,
try text_seg.addSection(self.allocator, "__text", "__TEXT", .{
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
continue;
}
@ -771,56 +635,17 @@ fn updateMetadata(self: *Zld) !void {
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,
});
try text_seg.addSection(self.allocator, "__ustring", "__TEXT", .{});
} else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
if (self.gcc_except_tab_section_index != null) continue;
self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len);
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__gcc_except_tab"),
.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,
});
try text_seg.addSection(self.allocator, "__gcc_except_tab", "__TEXT", .{});
} 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,
});
try text_seg.addSection(self.allocator, "__const", "__TEXT", .{});
}
continue;
}
@ -829,20 +654,7 @@ fn updateMetadata(self: *Zld) !void {
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,
});
try data_const_seg.addSection(self.allocator, "__const", "__DATA_CONST", .{});
continue;
}
@ -851,38 +663,17 @@ fn updateMetadata(self: *Zld) !void {
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,
});
try data_const_seg.addSection(self.allocator, "__const", "__DATA_CONST", .{});
} else if (mem.eql(u8, sectname, "__cfstring")) {
if (self.objc_cfstring_section_index != null) continue;
self.objc_cfstring_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.allocator, "__cfstring", "__DATA_CONST", .{});
} 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,
});
try data_seg.addSection(self.allocator, "__data", "__DATA", .{});
}
continue;
@ -932,19 +723,8 @@ fn updateMetadata(self: *Zld) !void {
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
const common_section_index = self.common_section_index orelse ind: {
self.common_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__common"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
try data_seg.addSection(self.allocator, "__common", "__DATA", .{
.flags = macho.S_ZEROFILL,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
break :ind self.common_section_index.?;
};
@ -1136,6 +916,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
.seg = self.data_const_segment_cmd_index.?,
.sect = self.data_const_section_index.?,
};
} else if (mem.eql(u8, sectname, "__cfstring")) {
break :blk .{
.seg = self.data_const_segment_cmd_index.?,
.sect = self.objc_cfstring_section_index.?,
};
}
break :blk .{
.seg = self.data_segment_cmd_index.?,
@ -1200,6 +985,7 @@ fn sortSections(self: *Zld) !void {
&self.mod_init_func_section_index,
&self.mod_term_func_section_index,
&self.data_const_section_index,
&self.objc_cfstring_section_index,
};
for (indices) |maybe_index| {
const new_index: u16 = if (maybe_index.*) |index| blk: {
@ -2240,18 +2026,8 @@ fn populateMetadata(self: *Zld) !void {
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__PAGEZERO"),
.vmaddr = 0,
.Segment = SegmentCommand.empty("__PAGEZERO", .{
.vmsize = 0x100000000, // size always set to 4GB
.fileoff = 0,
.filesize = 0,
.maxprot = 0,
.initprot = 0,
.nsects = 0,
.flags = 0,
}),
});
}
@ -2259,18 +2035,10 @@ fn populateMetadata(self: *Zld) !void {
if (self.text_segment_cmd_index == null) {
self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__TEXT"),
.Segment = SegmentCommand.empty("__TEXT", .{
.vmaddr = 0x100000000, // always starts at 4GB
.vmsize = 0,
.fileoff = 0,
.filesize = 0,
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
.nsects = 0,
.flags = 0,
}),
});
}
@ -2283,19 +2051,9 @@ fn populateMetadata(self: *Zld) !void {
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__text"),
.segname = makeStaticString("__TEXT"),
.addr = 0,
.size = 0,
.offset = 0,
try text_seg.addSection(self.allocator, "__text", "__TEXT", .{
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
@ -2312,19 +2070,10 @@ fn populateMetadata(self: *Zld) !void {
.aarch64 => 3 * @sizeOf(u32),
else => unreachable, // unhandled architecture type
};
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__stubs"),
.segname = makeStaticString("__TEXT"),
.addr = 0,
.size = 0,
.offset = 0,
try text_seg.addSection(self.allocator, "__stubs", "__TEXT", .{
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved1 = 0,
.reserved2 = stub_size,
.reserved3 = 0,
});
}
@ -2341,37 +2090,19 @@ fn populateMetadata(self: *Zld) !void {
.aarch64 => 6 * @sizeOf(u32),
else => unreachable,
};
try text_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__stub_helper"),
.segname = makeStaticString("__TEXT"),
.addr = 0,
try text_seg.addSection(self.allocator, "__stub_helper", "__TEXT", .{
.size = stub_helper_size,
.offset = 0,
.@"align" = alignment,
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
if (self.data_const_segment_cmd_index == null) {
self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__DATA_CONST"),
.vmaddr = 0,
.vmsize = 0,
.fileoff = 0,
.filesize = 0,
.Segment = SegmentCommand.empty("__DATA_CONST", .{
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.nsects = 0,
.flags = 0,
}),
});
}
@ -2379,37 +2110,18 @@ fn populateMetadata(self: *Zld) !void {
if (self.got_section_index == null) {
const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
self.got_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__got"),
.segname = makeStaticString("__DATA_CONST"),
.addr = 0,
.size = 0,
.offset = 0,
try data_const_seg.addSection(self.allocator, "__got", "__DATA_CONST", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
if (self.data_segment_cmd_index == null) {
self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__DATA"),
.vmaddr = 0,
.vmsize = 0,
.fileoff = 0,
.filesize = 0,
.Segment = SegmentCommand.empty("__DATA", .{
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.nsects = 0,
.flags = 0,
}),
});
}
@ -2417,56 +2129,26 @@ fn populateMetadata(self: *Zld) !void {
if (self.la_symbol_ptr_section_index == null) {
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.allocator, .{
.sectname = makeStaticString("__la_symbol_ptr"),
.segname = makeStaticString("__DATA"),
.addr = 0,
.size = 0,
.offset = 0,
try data_seg.addSection(self.allocator, "__la_symbol_ptr", "__DATA", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = macho.S_LAZY_SYMBOL_POINTERS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
if (self.data_section_index == null) {
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
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,
try data_seg.addSection(self.allocator, "__data", "__DATA", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
.reloff = 0,
.nreloc = 0,
.flags = macho.S_REGULAR,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
}
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.allocator, .{
.Segment = SegmentCommand.empty(.{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString("__LINKEDIT"),
.vmaddr = 0,
.vmsize = 0,
.fileoff = 0,
.filesize = 0,
.Segment = SegmentCommand.empty("__LINKEDIT", .{
.maxprot = macho.VM_PROT_READ,
.initprot = macho.VM_PROT_READ,
.nsects = 0,
.flags = 0,
}),
});
}
@ -3469,13 +3151,6 @@ fn writeHeader(self: *Zld) !void {
try self.file.?.pwriteAll(mem.asBytes(&header), 0);
}
pub fn makeStaticString(bytes: []const u8) [16]u8 {
var buf = [_]u8{0} ** 16;
assert(bytes.len <= buf.len);
mem.copy(u8, &buf, bytes);
return buf;
}
fn makeString(self: *Zld, bytes: []const u8) !u32 {
if (self.strtab_dir.get(bytes)) |offset| {
log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });

View File

@ -9,7 +9,6 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const MachO = @import("../MachO.zig");
const makeStaticString = MachO.makeStaticString;
const padToIdeal = MachO.padToIdeal;
pub const LoadCommand = union(enum) {
@ -187,12 +186,70 @@ pub const SegmentCommand = struct {
inner: macho.segment_command_64,
sections: std.ArrayListUnmanaged(macho.section_64) = .{},
pub fn empty(inner: macho.segment_command_64) SegmentCommand {
return .{ .inner = inner };
const SegmentOptions = struct {
cmdsize: u32 = @sizeOf(macho.segment_command_64),
vmaddr: u64 = 0,
vmsize: u64 = 0,
fileoff: u64 = 0,
filesize: u64 = 0,
maxprot: macho.vm_prot_t = macho.VM_PROT_NONE,
initprot: macho.vm_prot_t = macho.VM_PROT_NONE,
nsects: u32 = 0,
flags: u32 = 0,
};
pub fn empty(comptime segname: []const u8, opts: SegmentOptions) SegmentCommand {
return .{
.inner = .{
.cmd = macho.LC_SEGMENT_64,
.cmdsize = opts.cmdsize,
.segname = makeStaticString(segname),
.vmaddr = opts.vmaddr,
.vmsize = opts.vmsize,
.fileoff = opts.fileoff,
.filesize = opts.filesize,
.maxprot = opts.maxprot,
.initprot = opts.initprot,
.nsects = opts.nsects,
.flags = opts.flags,
},
};
}
pub fn addSection(self: *SegmentCommand, alloc: *Allocator, section: macho.section_64) !void {
try self.sections.append(alloc, section);
const SectionOptions = struct {
addr: u64 = 0,
size: u64 = 0,
offset: u32 = 0,
@"align": u32 = 0,
reloff: u32 = 0,
nreloc: u32 = 0,
flags: u32 = macho.S_REGULAR,
reserved1: u32 = 0,
reserved2: u32 = 0,
reserved3: u32 = 0,
};
pub fn addSection(
self: *SegmentCommand,
alloc: *Allocator,
comptime sectname: []const u8,
comptime segname: []const u8,
opts: SectionOptions,
) !void {
try self.sections.append(alloc, .{
.sectname = makeStaticString(sectname),
.segname = makeStaticString(segname),
.addr = opts.addr,
.size = opts.size,
.offset = opts.offset,
.@"align" = opts.@"align",
.reloff = opts.reloff,
.nreloc = opts.nreloc,
.flags = opts.flags,
.reserved1 = opts.reserved1,
.reserved2 = opts.reserved2,
.reserved3 = opts.reserved3,
});
self.inner.cmdsize += @sizeOf(macho.section_64);
self.inner.nsects += 1;
}
@ -338,6 +395,13 @@ pub fn createLoadDylibCommand(
return dylib_cmd;
}
fn makeStaticString(bytes: []const u8) [16]u8 {
var buf = [_]u8{0} ** 16;
assert(bytes.len <= buf.len);
mem.copy(u8, &buf, bytes);
return buf;
}
fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {
var stream = io.fixedBufferStream(buffer);
var given = try LoadCommand.read(allocator, stream.reader());