mirror of
https://github.com/ziglang/zig.git
synced 2026-01-12 10:25:13 +00:00
macho: remove all Zld codepaths
This commit is contained in:
parent
5af13f35f9
commit
4b07da7090
@ -761,43 +761,34 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
|
||||
try self.addDataInCodeLC();
|
||||
try self.addCodeSignatureLC();
|
||||
|
||||
if (use_stage1) {
|
||||
try self.parseTextBlocks();
|
||||
try self.allocateTextSegment();
|
||||
try self.allocateDataConstSegment();
|
||||
try self.allocateDataSegment();
|
||||
self.allocateLinkeditSegment();
|
||||
try self.allocateTextBlocks();
|
||||
try self.flushZld();
|
||||
} else {
|
||||
try self.parseTextBlocks();
|
||||
try self.allocateGlobalSymbols();
|
||||
{
|
||||
log.debug("locals:", .{});
|
||||
for (self.locals.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("globals:", .{});
|
||||
for (self.globals.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("undefs:", .{});
|
||||
for (self.undefs.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("unresolved:", .{});
|
||||
for (self.unresolved.keys()) |key| {
|
||||
log.debug(" {d} => {s}", .{ key, self.unresolved.get(key).? });
|
||||
}
|
||||
log.debug("resolved:", .{});
|
||||
var it = self.symbol_resolver.iterator();
|
||||
while (it.next()) |entry| {
|
||||
log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
|
||||
}
|
||||
try self.parseTextBlocks();
|
||||
try self.allocateGlobalSymbols();
|
||||
{
|
||||
log.debug("locals:", .{});
|
||||
for (self.locals.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("globals:", .{});
|
||||
for (self.globals.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("undefs:", .{});
|
||||
for (self.undefs.items) |sym| {
|
||||
log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
|
||||
}
|
||||
log.debug("unresolved:", .{});
|
||||
for (self.unresolved.keys()) |key| {
|
||||
log.debug(" {d} => {s}", .{ key, self.unresolved.get(key).? });
|
||||
}
|
||||
log.debug("resolved:", .{});
|
||||
var it = self.symbol_resolver.iterator();
|
||||
while (it.next()) |entry| {
|
||||
log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
|
||||
}
|
||||
try self.writeAtoms();
|
||||
try self.flushModule(comp);
|
||||
}
|
||||
try self.writeAtoms();
|
||||
try self.writeDices();
|
||||
try self.flushModule(comp);
|
||||
}
|
||||
|
||||
if (!self.base.options.disable_lld_caching) {
|
||||
@ -1638,248 +1629,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
|
||||
return res;
|
||||
}
|
||||
|
||||
fn allocateTextSegment(self: *MachO) !void {
|
||||
const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
|
||||
seg.inner.fileoff = 0;
|
||||
seg.inner.vmaddr = base_vmaddr;
|
||||
|
||||
var sizeofcmds: u64 = 0;
|
||||
for (self.load_commands.items) |lc| {
|
||||
sizeofcmds += lc.cmdsize();
|
||||
}
|
||||
|
||||
try self.allocateSegment(self.text_segment_cmd_index.?, @sizeOf(macho.mach_header_64) + sizeofcmds);
|
||||
|
||||
// Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
|
||||
var min_alignment: u32 = 0;
|
||||
for (seg.sections.items) |sect| {
|
||||
const alignment = try math.powi(u32, 2, sect.@"align");
|
||||
min_alignment = math.max(min_alignment, alignment);
|
||||
}
|
||||
|
||||
assert(min_alignment > 0);
|
||||
const last_sect_idx = seg.sections.items.len - 1;
|
||||
const last_sect = seg.sections.items[last_sect_idx];
|
||||
const shift: u32 = blk: {
|
||||
const diff = seg.inner.filesize - last_sect.offset - last_sect.size;
|
||||
const factor = @divTrunc(diff, min_alignment);
|
||||
break :blk @intCast(u32, factor * min_alignment);
|
||||
};
|
||||
|
||||
if (shift > 0) {
|
||||
for (seg.sections.items) |*sect| {
|
||||
sect.offset += shift;
|
||||
sect.addr += shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateDataConstSegment(self: *MachO) !void {
|
||||
const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
|
||||
seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
|
||||
try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
|
||||
}
|
||||
|
||||
fn allocateDataSegment(self: *MachO) !void {
|
||||
const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
|
||||
seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
|
||||
try self.allocateSegment(self.data_segment_cmd_index.?, 0);
|
||||
}
|
||||
|
||||
fn allocateLinkeditSegment(self: *MachO) void {
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
|
||||
seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
|
||||
}
|
||||
|
||||
fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {
|
||||
const seg = &self.load_commands.items[index].Segment;
|
||||
|
||||
// Allocate the sections according to their alignment at the beginning of the segment.
|
||||
var start: u64 = offset;
|
||||
for (seg.sections.items) |*sect, sect_id| {
|
||||
const alignment = try math.powi(u32, 2, sect.@"align");
|
||||
const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
|
||||
const end_aligned = mem.alignForwardGeneric(u64, start_aligned + sect.size, alignment);
|
||||
const file_offset = @intCast(u32, seg.inner.fileoff + start_aligned);
|
||||
|
||||
blk: {
|
||||
if (index == self.data_segment_cmd_index.?) {
|
||||
if (self.bss_section_index) |idx| {
|
||||
if (sect_id == idx) {
|
||||
self.bss_file_offset = file_offset;
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
if (self.tlv_bss_section_index) |idx| {
|
||||
if (sect_id == idx) {
|
||||
self.tlv_bss_file_offset = file_offset;
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned);
|
||||
}
|
||||
|
||||
sect.addr = seg.inner.vmaddr + start_aligned;
|
||||
start = end_aligned;
|
||||
}
|
||||
|
||||
const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size);
|
||||
seg.inner.filesize = seg_size_aligned;
|
||||
seg.inner.vmsize = seg_size_aligned;
|
||||
}
|
||||
|
||||
fn allocateTextBlocks(self: *MachO) !void {
|
||||
var it = self.blocks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const match = entry.key_ptr.*;
|
||||
var block: *TextBlock = entry.value_ptr.*;
|
||||
|
||||
// Find the first block
|
||||
while (block.prev) |prev| {
|
||||
block = prev;
|
||||
}
|
||||
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
|
||||
var base_addr: u64 = sect.addr;
|
||||
const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
|
||||
|
||||
log.debug(" within section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
|
||||
log.debug(" {}", .{sect});
|
||||
|
||||
while (true) {
|
||||
const block_alignment = try math.powi(u32, 2, block.alignment);
|
||||
base_addr = mem.alignForwardGeneric(u64, base_addr, block_alignment);
|
||||
|
||||
const sym = &self.locals.items[block.local_sym_index];
|
||||
sym.n_value = base_addr;
|
||||
sym.n_sect = n_sect;
|
||||
|
||||
log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
|
||||
self.getString(sym.n_strx),
|
||||
base_addr,
|
||||
base_addr + block.size,
|
||||
block.size,
|
||||
block.alignment,
|
||||
});
|
||||
|
||||
// Update each alias (if any)
|
||||
for (block.aliases.items) |index| {
|
||||
const alias_sym = &self.locals.items[index];
|
||||
alias_sym.n_value = base_addr;
|
||||
alias_sym.n_sect = n_sect;
|
||||
}
|
||||
|
||||
// Update each symbol contained within the TextBlock
|
||||
for (block.contained.items) |sym_at_off| {
|
||||
const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
|
||||
contained_sym.n_value = base_addr + sym_at_off.offset;
|
||||
contained_sym.n_sect = n_sect;
|
||||
}
|
||||
|
||||
base_addr += block.size;
|
||||
|
||||
if (block.next) |next| {
|
||||
block = next;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update globals
|
||||
{
|
||||
var sym_it = self.symbol_resolver.valueIterator();
|
||||
while (sym_it.next()) |resolv| {
|
||||
if (resolv.where != .global) continue;
|
||||
|
||||
assert(resolv.local_sym_index != 0);
|
||||
const local_sym = self.locals.items[resolv.local_sym_index];
|
||||
const sym = &self.globals.items[resolv.where_index];
|
||||
sym.n_value = local_sym.n_value;
|
||||
sym.n_sect = local_sym.n_sect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn writeTextBlocks(self: *MachO) !void {
|
||||
var it = self.blocks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const match = entry.key_ptr.*;
|
||||
var block: *TextBlock = entry.value_ptr.*;
|
||||
|
||||
while (block.prev) |prev| {
|
||||
block = prev;
|
||||
}
|
||||
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
const sect_type = commands.sectionType(sect);
|
||||
|
||||
log.debug(" for section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
|
||||
log.debug(" {}", .{sect});
|
||||
|
||||
var code = try self.base.allocator.alloc(u8, sect.size);
|
||||
defer self.base.allocator.free(code);
|
||||
|
||||
const file_offset: u64 = blk: {
|
||||
if (self.data_segment_cmd_index.? == match.seg) {
|
||||
if (self.bss_section_index) |idx| {
|
||||
if (idx == match.sect) break :blk self.bss_file_offset.?;
|
||||
}
|
||||
if (self.tlv_bss_section_index) |idx| {
|
||||
if (idx == match.sect) break :blk self.tlv_bss_file_offset.?;
|
||||
}
|
||||
}
|
||||
break :blk sect.offset;
|
||||
};
|
||||
|
||||
if (sect_type == macho.S_ZEROFILL or sect_type == macho.S_THREAD_LOCAL_ZEROFILL) {
|
||||
mem.set(u8, code, 0);
|
||||
} else {
|
||||
var base_off: u64 = 0;
|
||||
|
||||
while (true) {
|
||||
const block_alignment = try math.powi(u32, 2, block.alignment);
|
||||
const aligned_base_off = mem.alignForwardGeneric(u64, base_off, block_alignment);
|
||||
|
||||
const sym = self.locals.items[block.local_sym_index];
|
||||
log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
|
||||
self.getString(sym.n_strx),
|
||||
aligned_base_off,
|
||||
aligned_base_off + block.size,
|
||||
block.size,
|
||||
block.alignment,
|
||||
});
|
||||
|
||||
try block.resolveRelocs(self);
|
||||
mem.copy(u8, code[aligned_base_off..][0..block.size], block.code.items);
|
||||
|
||||
// TODO NOP for machine code instead of just zeroing out
|
||||
const padding_len = aligned_base_off - base_off;
|
||||
mem.set(u8, code[base_off..][0..padding_len], 0);
|
||||
|
||||
base_off = aligned_base_off + block.size;
|
||||
|
||||
if (block.next) |next| {
|
||||
block = next;
|
||||
} else break;
|
||||
}
|
||||
|
||||
mem.set(u8, code[base_off..], 0);
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(code, file_offset);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
|
||||
const code = try self.base.allocator.alloc(u8, size);
|
||||
defer self.base.allocator.free(code);
|
||||
@ -2920,17 +2669,23 @@ fn parseTextBlocks(self: *MachO) !void {
|
||||
}
|
||||
|
||||
fn addDataInCodeLC(self: *MachO) !void {
|
||||
if (self.data_in_code_cmd_index == null) {
|
||||
self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
try self.load_commands.append(self.base.allocator, .{
|
||||
.LinkeditData = .{
|
||||
.cmd = macho.LC_DATA_IN_CODE,
|
||||
.cmdsize = @sizeOf(macho.linkedit_data_command),
|
||||
.dataoff = 0,
|
||||
.datasize = 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (self.data_in_code_cmd_index != null) return;
|
||||
self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
try self.load_commands.append(self.base.allocator, .{
|
||||
.LinkeditData = .{
|
||||
.cmd = macho.LC_DATA_IN_CODE,
|
||||
.cmdsize = @sizeOf(macho.linkedit_data_command),
|
||||
.dataoff = 0,
|
||||
.datasize = 0,
|
||||
},
|
||||
});
|
||||
const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
|
||||
const needed_size = 10 * @sizeOf(macho.data_in_code_entry);
|
||||
const dataoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.data_in_code_entry), null);
|
||||
log.debug("found data-in-code free space 0x{x} to 0x{x}", .{ dataoff, dataoff + needed_size });
|
||||
dice_cmd.dataoff = @intCast(u32, dataoff);
|
||||
dice_cmd.datasize = needed_size;
|
||||
self.load_commands_dirty = true;
|
||||
}
|
||||
|
||||
fn addCodeSignatureLC(self: *MachO) !void {
|
||||
@ -2982,42 +2737,6 @@ fn addLoadDylibLCs(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn flushZld(self: *MachO) !void {
|
||||
try self.writeTextBlocks();
|
||||
try self.setEntryPoint();
|
||||
try self.writeRebaseInfoTableZld();
|
||||
try self.writeBindInfoTableZld();
|
||||
try self.writeLazyBindInfoTableZld();
|
||||
try self.writeExportInfoZld();
|
||||
try self.writeDices();
|
||||
|
||||
{
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
}
|
||||
|
||||
try self.writeSymbolTable();
|
||||
try self.writeStringTableZld();
|
||||
|
||||
{
|
||||
// Seal __LINKEDIT size
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
|
||||
}
|
||||
|
||||
if (self.requires_adhoc_codesig) {
|
||||
try self.writeCodeSignaturePadding();
|
||||
}
|
||||
|
||||
try self.writeLoadCommands();
|
||||
try self.writeHeader();
|
||||
|
||||
if (self.requires_adhoc_codesig) {
|
||||
try self.writeCodeSignature();
|
||||
}
|
||||
}
|
||||
|
||||
fn setEntryPoint(self: *MachO) !void {
|
||||
if (self.base.options.output_mode != .Exe) return;
|
||||
|
||||
@ -3039,343 +2758,6 @@ fn setEntryPoint(self: *MachO) !void {
|
||||
self.load_commands_dirty = true;
|
||||
}
|
||||
|
||||
fn writeRebaseInfoTableZld(self: *MachO) !void {
|
||||
var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
|
||||
defer pointers.deinit();
|
||||
|
||||
{
|
||||
var it = self.blocks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const match = entry.key_ptr.*;
|
||||
var block: *TextBlock = entry.value_ptr.*;
|
||||
|
||||
if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
|
||||
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
|
||||
while (true) {
|
||||
const sym = self.locals.items[block.local_sym_index];
|
||||
const base_offset = sym.n_value - seg.inner.vmaddr;
|
||||
|
||||
for (block.rebases.items) |offset| {
|
||||
try pointers.append(.{
|
||||
.offset = base_offset + offset,
|
||||
.segment_id = match.seg,
|
||||
});
|
||||
}
|
||||
|
||||
if (block.prev) |prev| {
|
||||
block = prev;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const size = try bind.rebaseInfoSize(pointers.items);
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
try bind.writeRebaseInfo(pointers.items, stream.writer());
|
||||
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
|
||||
dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64)));
|
||||
seg.inner.filesize += dyld_info.rebase_size;
|
||||
|
||||
log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size });
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
|
||||
}
|
||||
|
||||
fn writeBindInfoTableZld(self: *MachO) !void {
|
||||
var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
|
||||
defer pointers.deinit();
|
||||
|
||||
{
|
||||
var it = self.blocks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const match = entry.key_ptr.*;
|
||||
var block: *TextBlock = entry.value_ptr.*;
|
||||
|
||||
if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
|
||||
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
|
||||
while (true) {
|
||||
const sym = self.locals.items[block.local_sym_index];
|
||||
const base_offset = sym.n_value - seg.inner.vmaddr;
|
||||
|
||||
for (block.bindings.items) |binding| {
|
||||
const bind_sym = self.undefs.items[binding.local_sym_index];
|
||||
try pointers.append(.{
|
||||
.offset = binding.offset + base_offset,
|
||||
.segment_id = match.seg,
|
||||
.dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(bind_sym.n_strx),
|
||||
});
|
||||
}
|
||||
|
||||
if (block.prev) |prev| {
|
||||
block = prev;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const size = try bind.bindInfoSize(pointers.items);
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
try bind.writeBindInfo(pointers.items, stream.writer());
|
||||
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
dyld_info.bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
|
||||
seg.inner.filesize += dyld_info.bind_size;
|
||||
|
||||
log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size });
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
|
||||
}
|
||||
|
||||
fn writeLazyBindInfoTableZld(self: *MachO) !void {
|
||||
var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
|
||||
defer pointers.deinit();
|
||||
|
||||
if (self.la_symbol_ptr_section_index) |sect| blk: {
|
||||
var atom = self.blocks.get(.{
|
||||
.seg = self.data_segment_cmd_index.?,
|
||||
.sect = sect,
|
||||
}) orelse break :blk;
|
||||
const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
|
||||
while (true) {
|
||||
const sym = self.locals.items[atom.local_sym_index];
|
||||
const base_offset = sym.n_value - seg.inner.vmaddr;
|
||||
|
||||
for (atom.lazy_bindings.items) |binding| {
|
||||
const bind_sym = self.undefs.items[binding.local_sym_index];
|
||||
try pointers.append(.{
|
||||
.offset = binding.offset + base_offset,
|
||||
.segment_id = self.data_segment_cmd_index.?,
|
||||
.dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(bind_sym.n_strx),
|
||||
});
|
||||
}
|
||||
if (atom.prev) |prev| {
|
||||
atom = prev;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
const size = try bind.lazyBindInfoSize(pointers.items);
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
try bind.writeLazyBindInfo(pointers.items, stream.writer());
|
||||
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
dyld_info.lazy_bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
|
||||
seg.inner.filesize += dyld_info.lazy_bind_size;
|
||||
|
||||
log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
|
||||
try self.populateLazyBindOffsetsInStubHelper(buffer);
|
||||
}
|
||||
|
||||
fn writeExportInfoZld(self: *MachO) !void {
|
||||
var trie: Trie = .{};
|
||||
defer trie.deinit(self.base.allocator);
|
||||
|
||||
const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const base_address = text_segment.inner.vmaddr;
|
||||
|
||||
// TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
|
||||
log.debug("writing export trie", .{});
|
||||
|
||||
for (self.globals.items) |sym| {
|
||||
const sym_name = self.getString(sym.n_strx);
|
||||
log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
|
||||
|
||||
try trie.put(self.base.allocator, .{
|
||||
.name = sym_name,
|
||||
.vmaddr_offset = sym.n_value - base_address,
|
||||
.export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
|
||||
});
|
||||
}
|
||||
|
||||
try trie.finalize(self.base.allocator);
|
||||
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, trie.size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const nwritten = try trie.write(stream.writer());
|
||||
assert(nwritten == trie.size);
|
||||
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
dyld_info.export_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
|
||||
seg.inner.filesize += dyld_info.export_size;
|
||||
|
||||
log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
|
||||
}
|
||||
|
||||
fn writeSymbolTable(self: *MachO) !void {
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
|
||||
var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
|
||||
defer locals.deinit();
|
||||
try locals.appendSlice(self.locals.items);
|
||||
|
||||
if (self.has_stabs) {
|
||||
for (self.objects.items) |object| {
|
||||
if (object.debug_info == null) continue;
|
||||
|
||||
// Open scope
|
||||
try locals.ensureUnusedCapacity(3);
|
||||
locals.appendAssumeCapacity(.{
|
||||
.n_strx = try self.makeString(object.tu_comp_dir.?),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
locals.appendAssumeCapacity(.{
|
||||
.n_strx = try self.makeString(object.tu_name.?),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
locals.appendAssumeCapacity(.{
|
||||
.n_strx = try self.makeString(object.name),
|
||||
.n_type = macho.N_OSO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 1,
|
||||
.n_value = object.mtime orelse 0,
|
||||
});
|
||||
|
||||
for (object.text_blocks.items) |block| {
|
||||
if (block.stab) |stab| {
|
||||
const nlists = try stab.asNlists(block.local_sym_index, self);
|
||||
defer self.base.allocator.free(nlists);
|
||||
try locals.appendSlice(nlists);
|
||||
} else {
|
||||
for (block.contained.items) |sym_at_off| {
|
||||
const stab = sym_at_off.stab orelse continue;
|
||||
const nlists = try stab.asNlists(sym_at_off.local_sym_index, self);
|
||||
defer self.base.allocator.free(nlists);
|
||||
try locals.appendSlice(nlists);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close scope
|
||||
try locals.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const nlocals = locals.items.len;
|
||||
const nexports = self.globals.items.len;
|
||||
const nundefs = self.undefs.items.len;
|
||||
|
||||
const locals_off = symtab.symoff;
|
||||
const locals_size = nlocals * @sizeOf(macho.nlist_64);
|
||||
log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
|
||||
|
||||
const exports_off = locals_off + locals_size;
|
||||
const exports_size = nexports * @sizeOf(macho.nlist_64);
|
||||
log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), exports_off);
|
||||
|
||||
const undefs_off = exports_off + exports_size;
|
||||
const undefs_size = nundefs * @sizeOf(macho.nlist_64);
|
||||
log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off);
|
||||
|
||||
symtab.nsyms = @intCast(u32, nlocals + nexports + nundefs);
|
||||
seg.inner.filesize += locals_size + exports_size + undefs_size;
|
||||
|
||||
// Update dynamic symbol table.
|
||||
const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
|
||||
dysymtab.nlocalsym = @intCast(u32, nlocals);
|
||||
dysymtab.iextdefsym = dysymtab.nlocalsym;
|
||||
dysymtab.nextdefsym = @intCast(u32, nexports);
|
||||
dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
|
||||
dysymtab.nundefsym = @intCast(u32, nundefs);
|
||||
|
||||
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stubs = &text_segment.sections.items[self.stubs_section_index.?];
|
||||
const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const got = &data_const_segment.sections.items[self.got_section_index.?];
|
||||
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
|
||||
const nstubs = @intCast(u32, self.stubs_map.keys().len);
|
||||
const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
|
||||
|
||||
dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
|
||||
|
||||
const needed_size = dysymtab.nindirectsyms * @sizeOf(u32);
|
||||
seg.inner.filesize += needed_size;
|
||||
|
||||
log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
|
||||
dysymtab.indirectsymoff,
|
||||
dysymtab.indirectsymoff + needed_size,
|
||||
});
|
||||
|
||||
var buf = try self.base.allocator.alloc(u8, needed_size);
|
||||
defer self.base.allocator.free(buf);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buf);
|
||||
var writer = stream.writer();
|
||||
|
||||
stubs.reserved1 = 0;
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
got.reserved1 = nstubs;
|
||||
for (self.got_entries_map.keys()) |key| {
|
||||
switch (key.where) {
|
||||
.undef => {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
|
||||
},
|
||||
.local => {
|
||||
try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *MachO) void {
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
|
||||
@ -3812,12 +3194,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
|
||||
try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
|
||||
}
|
||||
|
||||
// // Resolve relocations
|
||||
// try decl.link.macho.resolveRelocs(self);
|
||||
// // TODO this requires further investigation: should we dispose of resolved relocs, or keep them
|
||||
// // so that we can reapply them when moving/growing sections?
|
||||
// decl.link.macho.relocs.clearAndFree(self.base.allocator);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@ -5003,9 +4379,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
fn writeDices(self: *MachO) !void {
|
||||
if (!self.has_dices) return;
|
||||
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
|
||||
const fileoff = seg.inner.fileoff + seg.inner.filesize;
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var buf = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer buf.deinit();
|
||||
@ -5043,15 +4418,26 @@ fn writeDices(self: *MachO) !void {
|
||||
} else break;
|
||||
}
|
||||
|
||||
const datasize = @intCast(u32, buf.items.len);
|
||||
const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
|
||||
const allocated_size = self.allocatedSizeLinkedit(dice_cmd.dataoff);
|
||||
const needed_size = @intCast(u32, buf.items.len);
|
||||
|
||||
dice_cmd.dataoff = @intCast(u32, fileoff);
|
||||
dice_cmd.datasize = datasize;
|
||||
seg.inner.filesize += datasize;
|
||||
if (needed_size > allocated_size) {
|
||||
dice_cmd.datasize = 0;
|
||||
dice_cmd.dataoff = @intCast(u32, self.findFreeSpaceLinkedit(
|
||||
needed_size,
|
||||
@alignOf(macho.data_in_code_entry),
|
||||
dice_cmd.dataoff,
|
||||
));
|
||||
}
|
||||
dice_cmd.datasize = needed_size;
|
||||
log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
|
||||
dice_cmd.dataoff,
|
||||
dice_cmd.dataoff + dice_cmd.datasize,
|
||||
});
|
||||
|
||||
log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize });
|
||||
|
||||
try self.base.file.?.pwriteAll(buf.items, fileoff);
|
||||
try self.base.file.?.pwriteAll(buf.items, dice_cmd.dataoff);
|
||||
self.load_commands_dirty = true;
|
||||
}
|
||||
|
||||
fn writeCodeSignaturePadding(self: *MachO) !void {
|
||||
@ -5130,7 +4516,7 @@ fn writeExportInfo(self: *MachO) !void {
|
||||
|
||||
for (self.globals.items) |sym| {
|
||||
const sym_name = self.getString(sym.n_strx);
|
||||
log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
|
||||
log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
|
||||
|
||||
try trie.put(self.base.allocator, .{
|
||||
.name = sym_name,
|
||||
@ -5453,30 +4839,16 @@ fn writeStringTable(self: *MachO) !void {
|
||||
self.strtab_needs_relocation = false;
|
||||
}
|
||||
symtab.strsize = @intCast(u32, needed_size);
|
||||
log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
|
||||
log.debug("writing string table from 0x{x} to 0x{x}", .{
|
||||
symtab.stroff,
|
||||
symtab.stroff + symtab.strsize,
|
||||
});
|
||||
|
||||
try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
|
||||
self.load_commands_dirty = true;
|
||||
self.strtab_dirty = false;
|
||||
}
|
||||
|
||||
fn writeStringTableZld(self: *MachO) !void {
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
|
||||
seg.inner.filesize += symtab.strsize;
|
||||
|
||||
log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
|
||||
|
||||
try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
|
||||
|
||||
if (symtab.strsize > self.strtab.items.len) {
|
||||
// This is potentially the last section, so we need to pad it out.
|
||||
try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn updateLinkeditSegmentSizes(self: *MachO) !void {
|
||||
if (!self.load_commands_dirty) return;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user