Commit 737a8bf204

Jakub Konka <kubkon@jakubkonka.com>
2020-10-01 20:20:01
Redo local symbols and offsets tracking to match Elf's approach
1 parent 2ba23ab
Changed files (2)
src/link/MachO.zig
@@ -149,19 +149,27 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
 const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib";
 
 pub const TextBlock = struct {
-    /// Index into the symbol table
-    symbol_table_index: ?u32,
+    /// Each decl always gets a local symbol with the fully qualified name.
+    /// The vaddr and size are found here directly.
+    /// The file offset is found by computing the vaddr offset from the section vaddr
+    /// the symbol references, and adding that to the file offset of the section.
+    /// If this field is 0, it means the codegen size = 0 and there is no symbol or
+    /// offset table entry.
+    local_sym_index: u32,
     /// Index into offset table
-    offset_table_index: ?u32,
+    /// This field is undefined for symbols with size = 0.
+    offset_table_index: u32,
     /// Size of this text block
+    /// Unlike in Elf, we need to store the size of this symbol as part of
+    /// the TextBlock since macho.nlist_64 lacks this information.
     size: u64,
     /// Points to the previous and next neighbours
     prev: ?*TextBlock,
     next: ?*TextBlock,
 
     pub const empty = TextBlock{
-        .symbol_table_index = null,
-        .offset_table_index = null,
+        .local_sym_index = 0,
+        .offset_table_index = undefined,
         .size = 0,
         .prev = null,
         .next = null,
@@ -190,6 +198,15 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
 
     self.base.file = file;
 
+    // Index 0 is always a null symbol.
+    try self.local_symbols.append(allocator, .{
+        .n_strx = 0,
+        .n_type = 0,
+        .n_sect = 0,
+        .n_desc = 0,
+        .n_value = 0,
+    });
+
     switch (options.output_mode) {
         .Exe => {},
         .Obj => {},
@@ -717,26 +734,26 @@ pub fn deinit(self: *MachO) void {
 }
 
 pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
-    if (decl.link.macho.symbol_table_index) |_| return;
+    if (decl.link.macho.local_sym_index != 0) return;
 
     try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
     try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
 
     log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
-    decl.link.macho.symbol_table_index = @intCast(u32, self.local_symbols.items.len);
+    decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);
     _ = self.local_symbols.addOneAssumeCapacity();
 
     decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);
     _ = self.offset_table.addOneAssumeCapacity();
 
-    self.local_symbols.items[decl.link.macho.symbol_table_index.?] = .{
+    self.local_symbols.items[decl.link.macho.local_sym_index] = .{
         .n_strx = 0,
         .n_type = 0,
         .n_sect = 0,
         .n_desc = 0,
         .n_value = 0,
     };
-    self.offset_table.items[decl.link.macho.offset_table_index.?] = 0;
+    self.offset_table.items[decl.link.macho.offset_table_index] = 0;
 }
 
 pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
@@ -761,7 +778,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
     log.debug("generated code {}\n", .{code});
 
     const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
-    const symbol = &self.local_symbols.items[decl.link.macho.symbol_table_index.?];
+    const symbol = &self.local_symbols.items[decl.link.macho.local_sym_index];
 
     const decl_name = mem.spanZ(decl.name);
     const name_str_index = try self.makeString(decl_name);
@@ -776,10 +793,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
         .n_desc = 0,
         .n_value = addr,
     };
-    self.offset_table.items[decl.link.macho.offset_table_index.?] = addr;
+    self.offset_table.items[decl.link.macho.offset_table_index] = addr;
 
-    try self.writeSymbol(decl.link.macho.symbol_table_index.?);
-    try self.writeOffsetTableEntry(decl.link.macho.offset_table_index.?);
+    try self.writeSymbol(decl.link.macho.local_sym_index);
+    try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
 
     const text_section = self.sections.items[self.text_section_index.?];
     const section_offset = symbol.n_value - text_section.addr;
@@ -805,8 +822,8 @@ pub fn updateDeclExports(
     defer tracy.end();
 
     try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
-    if (decl.link.macho.symbol_table_index == null) return;
-    const decl_sym = &self.local_symbols.items[decl.link.macho.symbol_table_index.?];
+    if (decl.link.macho.local_sym_index == 0) return;
+    const decl_sym = &self.local_symbols.items[decl.link.macho.local_sym_index];
 
     for (exports) |exp| {
         if (exp.options.section) |section_name| {
@@ -867,7 +884,8 @@ pub fn updateDeclExports(
 pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}
 
 pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
-    return self.local_symbols.items[decl.link.macho.symbol_table_index.?].n_value;
+    assert(decl.link.macho.local_sym_index != 0);
+    return self.local_symbols.items[decl.link.macho.local_sym_index].n_value;
 }
 
 pub fn populateMissingMetadata(self: *MachO) !void {
@@ -1126,17 +1144,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
         });
         self.cmd_table_dirty = true;
     }
-    if (self.dyld_stub_binder_index == null) {
-        self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);
-        const name = try self.makeString("dyld_stub_binder");
-        try self.undef_symbols.append(self.base.allocator, .{
-            .n_strx = name,
-            .n_type = macho.N_UNDF | macho.N_EXT,
-            .n_sect = 0,
-            .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
-            .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;
@@ -1175,6 +1182,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
             symtab.strsize = file_size;
         }
     }
+    if (self.dyld_stub_binder_index == null) {
+        self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);
+        const name = try self.makeString("dyld_stub_binder");
+        try self.undef_symbols.append(self.base.allocator, .{
+            .n_strx = name,
+            .n_type = macho.N_UNDF | macho.N_EXT,
+            .n_sect = 0,
+            .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
+            .n_value = 0,
+        });
+    }
 }
 
 fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
@@ -1184,7 +1202,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
     var block_placement: ?*TextBlock = null;
     const addr = blk: {
         if (self.last_text_block) |last| {
-            const last_symbol = self.local_symbols.items[last.symbol_table_index.?];
+            const last_symbol = self.local_symbols.items[last.local_sym_index];
             // TODO pad out with NOPs and reenable
             // const ideal_capacity = last.size * alloc_num / alloc_den;
             // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity;
src/codegen.zig
@@ -1532,7 +1532,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                             if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
                                 const func = func_val.func;
                                 const got = &macho_file.sections.items[macho_file.got_section_index.?];
-                                const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index.? * @sizeOf(u64);
+                                const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
                                 // Here, we store the got address in %rax, and then call %rax
                                 // movabsq [addr], %rax
                                 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
@@ -2591,7 +2591,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                         } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
                             const decl = payload.decl;
                             const got = &macho_file.sections.items[macho_file.got_section_index.?];
-                            const got_addr = got.addr + decl.link.macho.offset_table_index.? * ptr_bytes;
+                            const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes;
                             return MCValue{ .memory = got_addr };
                         } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
                             const decl = payload.decl;