Commit 5a7105401c
Changed files (1)
src
link
src/link/MachO.zig
@@ -262,6 +262,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
dysymtab.iundefsym = nlocals + nglobals;
dysymtab.nundefsym = nundefs;
}
+ {
+ // update LC_MAIN with entry offset
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
+ main_cmd.entryoff = self.entry_addr.? - text_segment.vmaddr;
+ }
{
var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
for (self.load_commands.items) |cmd| {
@@ -817,8 +823,6 @@ pub fn updateDeclExports(
.Strong => blk: {
if (mem.eql(u8, exp.options.name, "_start")) {
self.entry_addr = decl_sym.n_value;
- const cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
- cmd.entryoff = decl_sym.n_value;
}
break :blk macho.REFERENCE_FLAG_DEFINED;
},
@@ -985,8 +989,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.reserved3 = 0,
});
- data_segment.vmsize = file_size;
- data_segment.filesize = file_size;
+ const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
+ data_segment.vmsize = segment_size;
+ data_segment.filesize = segment_size;
data_segment.fileoff = off;
log.debug("initial got section {}\n", .{self.sections.items[self.got_section_index.?]});
@@ -1131,6 +1136,24 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.n_value = 0,
});
}
+ {
+ const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
+ if (dyld_info.export_off == 0) {
+ const nsyms = self.base.options.symbol_count_hint;
+ const file_size = @sizeOf(u64) * nsyms;
+ const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
+ log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
+ dyld_info.export_off = off;
+ dyld_info.export_size = @intCast(u32, file_size);
+
+ const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
+ linkedit.vmsize = 4 * segment_size;
+ linkedit.fileoff = off;
+
+ log.debug("updated linkedit segment {}\n", .{linkedit});
+ }
+ }
{
const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
@@ -1141,12 +1164,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
symtab.symoff = off;
symtab.nsyms = @intCast(u32, nsyms);
-
- linkedit.vmsize += file_size;
- linkedit.fileoff = off;
- linkedit.filesize += file_size;
-
- log.debug("updated linkedit segment {}\n", .{linkedit});
}
if (symtab.stroff == 0) {
try self.string_table.append(self.base.allocator, 0);
@@ -1155,11 +1172,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
symtab.stroff = off;
symtab.strsize = file_size;
-
- linkedit.vmsize += file_size;
- linkedit.filesize += file_size;
-
- log.debug("updated linkedit segment {}\n", .{linkedit});
}
}
}
@@ -1291,6 +1303,15 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
return test_end;
}
}
+ if (self.dyld_info_cmd_index) |dyld_info_index| {
+ const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo;
+ const tight_size = dyld_info.export_size;
+ const increased_size = satMul(tight_size, alloc_num) / alloc_den;
+ const test_end = dyld_info.export_off + increased_size;
+ if (end > dyld_info.export_off and start < test_end) {
+ return test_end;
+ }
+ }
if (self.symtab_cmd_index) |symtab_index| {
const symtab = self.load_commands.items[symtab_index].Symtab;
{
@@ -1324,6 +1345,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 {
if (section.offset <= start) continue;
if (section.offset < min_pos) min_pos = section.offset;
}
+ if (self.dyld_info_cmd_index) |dyld_info_index| {
+ const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo;
+ if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
+ }
if (self.symtab_cmd_index) |symtab_index| {
const symtab = self.load_commands.items[symtab_index].Symtab;
if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
@@ -1380,7 +1405,7 @@ fn writeAllUndefSymbols(self: *MachO) !void {
}
fn writeExportTrie(self: *MachO) !void {
- // TODO
+ // TODO implement mechanism for generating a prefix tree of the exported symbols
// single branch export trie
var buf = [_]u8{0} ** 24;
buf[0] = 0; // root node
@@ -1388,10 +1413,16 @@ fn writeExportTrie(self: *MachO) !void {
mem.copy(u8, buf[2..], "_start");
buf[8] = 0;
buf[9] = 9 + 1;
- const written = try std.debug.leb.writeULEB128Mem(buf[12..], self.entry_addr.?);
+
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const addr = self.entry_addr.? - text_segment.vmaddr;
+ const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr);
buf[10] = @intCast(u8, written) + 1;
buf[11] = 0;
log.debug("WAT = {}, {x}\n", .{ written, buf[0..] });
+
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
+ try self.base.file.?.pwriteAll(buf[0..], dyld_info.export_off);
}
fn writeStringTable(self: *MachO) !void {
@@ -1409,6 +1440,10 @@ fn writeStringTable(self: *MachO) !void {
log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
+
+ // FIXME
+ const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff;
}
/// Writes Mach-O file header.