diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-08 22:26:18 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-13 23:54:46 +0100 |
| commit | 44a052a65f5c59b02383178f36fcc231df28b49f (patch) | |
| tree | 55bb58983ccd0908b4b8f1337af6ff0321b204ae | |
| parent | 2f7cd7119387b517b07e5feb02a13e69651fe9eb (diff) | |
| download | zig-44a052a65f5c59b02383178f36fcc231df28b49f.tar.gz zig-44a052a65f5c59b02383178f36fcc231df28b49f.zip | |
macho: write out stubs for new externs only
| -rw-r--r-- | src/codegen.zig | 30 | ||||
| -rw-r--r-- | src/link/MachO.zig | 93 |
2 files changed, 68 insertions, 55 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 7100227db0..84148fcdd4 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1862,18 +1862,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } else if (func_value.castTag(.extern_fn)) |func_payload| { const decl = func_payload.data; const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name}); - defer self.bin_file.allocator.free(decl_name); - const name = try macho_file.makeString(decl_name); - const symbol = macho_file.undef_symbols.items.len; - try macho_file.undef_symbols.append(self.bin_file.allocator, .{ - .n_strx = name, - .n_type = std.macho.N_UNDF | std.macho.N_EXT, - .n_sect = 0, - .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, - .n_value = 0, - }); + const exists: bool = macho_file.externs.contains(decl_name); + const symbol: u32 = blk: { + if (macho_file.externs.get(decl_name)) |index| { + self.bin_file.allocator.free(decl_name); + break :blk index; + } else { + const extern_index = @intCast(u32, macho_file.undef_symbols.items.len - 1); // TODO + try macho_file.externs.putNoClobber(self.bin_file.allocator, decl_name, extern_index); + const name = try macho_file.makeString(decl_name); + try macho_file.undef_symbols.append(self.bin_file.allocator, .{ + .n_strx = name, + .n_type = std.macho.N_UNDF | std.macho.N_EXT, + .n_sect = 0, + .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, + .n_value = 0, + }); + break :blk extern_index; + } + }; try macho_file.stub_fixups.append(self.bin_file.allocator, .{ .symbol = symbol, + .exists = exists, .start = self.code.items.len, .len = 4, }); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index e83fab6294..3c876bf59d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -167,9 +167,11 @@ last_text_block: ?*TextBlock = null, pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, +externs: std.StringHashMapUnmanaged(u32) = .{}, pub const StubFixup = struct { - symbol: usize, + symbol: u32, + exists: bool, start: usize, len: usize, }; @@ -1263,56 +1265,57 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { const stub_h = &text_segment.sections.items[self.stub_helper_section_index.?]; const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; const la_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; - for (self.stub_fixups.items) |fixup, idx| { - const i = @intCast(u32, idx); + for (self.stub_fixups.items) |fixup| { // TODO increment offset for stub writing - const stub_addr = stubs.addr + i * stubs.reserved2; + const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; const text_addr = symbol.n_value + fixup.start; const displacement = @intCast(u32, stub_addr - text_addr); var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); - const end = stub_h.addr + self.next_stub_helper_off.? - stub_h.offset; - var buf: [@sizeOf(u64)]u8 = undefined; - mem.writeIntLittle(u64, &buf, end); - try self.base.file.?.pwriteAll(&buf, la_ptr.offset + i * @sizeOf(u64)); - - const la_ptr_addr = la_ptr.addr + i * @sizeOf(u64); - const displacement2 = la_ptr_addr - stub_addr; - var ccode: [2 * @sizeOf(u32)]u8 = undefined; - mem.writeIntLittle(u32, ccode[0..4], aarch64.Instruction.ldr(.x16, .{ - .literal = @intCast(u19, displacement2 / 4), - }).toU32()); - mem.writeIntLittle(u32, ccode[4..8], aarch64.Instruction.br(.x16).toU32()); - try self.base.file.?.pwriteAll(&ccode, stubs.offset + i * stubs.reserved2); - - const displacement3 = @intCast(i64, stub_h.addr) - @intCast(i64, end + 4); - var cccode: [3 * @sizeOf(u32)]u8 = undefined; - mem.writeIntLittle(u32, cccode[0..4], aarch64.Instruction.ldr(.w16, .{ - .literal = 0x2, - }).toU32()); - mem.writeIntLittle(u32, cccode[4..8], aarch64.Instruction.b(@intCast(i28, displacement3)).toU32()); - mem.writeIntLittle(u32, cccode[8..12], i * 0xd); - try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); - self.next_stub_helper_off = self.next_stub_helper_off.? + 3 * @sizeOf(u32); - - try self.rebase_info_table.symbols.append(self.base.allocator, .{ - .segment = 3, - .offset = i * stubs.reserved2, - }); - self.rebase_info_dirty = true; - - const sym = self.undef_symbols.items[fixup.symbol]; - const name_str = self.getString(sym.n_strx); - var name = try self.base.allocator.alloc(u8, name_str.len); - mem.copy(u8, name, name_str); - try self.lazy_binding_info_table.symbols.append(self.base.allocator, .{ - .segment = 3, - .offset = i * @sizeOf(u64), - .dylib_ordinal = 1, - .name = name, - }); - self.lazy_binding_info_dirty = true; + if (!fixup.exists) { + const end = stub_h.addr + self.next_stub_helper_off.? - stub_h.offset; + var buf: [@sizeOf(u64)]u8 = undefined; + mem.writeIntLittle(u64, &buf, end); + try self.base.file.?.pwriteAll(&buf, la_ptr.offset + fixup.symbol * @sizeOf(u64)); + + const la_ptr_addr = la_ptr.addr + fixup.symbol * @sizeOf(u64); + const displacement2 = la_ptr_addr - stub_addr; + var ccode: [2 * @sizeOf(u32)]u8 = undefined; + mem.writeIntLittle(u32, ccode[0..4], aarch64.Instruction.ldr(.x16, .{ + .literal = @intCast(u19, displacement2 / 4), + }).toU32()); + mem.writeIntLittle(u32, ccode[4..8], aarch64.Instruction.br(.x16).toU32()); + try self.base.file.?.pwriteAll(&ccode, stubs.offset + fixup.symbol * stubs.reserved2); + + const displacement3 = @intCast(i64, stub_h.addr) - @intCast(i64, end + 4); + var cccode: [3 * @sizeOf(u32)]u8 = undefined; + mem.writeIntLittle(u32, cccode[0..4], aarch64.Instruction.ldr(.w16, .{ + .literal = 0x2, + }).toU32()); + mem.writeIntLittle(u32, cccode[4..8], aarch64.Instruction.b(@intCast(i28, displacement3)).toU32()); + mem.writeIntLittle(u32, cccode[8..12], fixup.symbol * 0xd); + try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); + self.next_stub_helper_off = self.next_stub_helper_off.? + 3 * @sizeOf(u32); + + try self.rebase_info_table.symbols.append(self.base.allocator, .{ + .segment = 3, + .offset = fixup.symbol * stubs.reserved2, + }); + self.rebase_info_dirty = true; + + const sym = self.undef_symbols.items[fixup.symbol + 1]; + const name_str = self.getString(sym.n_strx); + var name = try self.base.allocator.alloc(u8, name_str.len); + mem.copy(u8, name, name_str); + try self.lazy_binding_info_table.symbols.append(self.base.allocator, .{ + .segment = 3, + .offset = fixup.symbol * @sizeOf(u64), + .dylib_ordinal = 1, + .name = name, + }); + self.lazy_binding_info_dirty = true; + } } self.stub_fixups.shrinkRetainingCapacity(0); |
