Commit 7d40aaad2b
Changed files (4)
src
link
MachO
test
stage2
src/link/MachO/imports.zig
@@ -20,13 +20,15 @@ pub const ExternSymbol = struct {
/// dylibs.
dylib_ordinal: i64 = 0,
+ /// Id of the segment where this symbol is defined (will have its address
+ /// resolved).
segment: u16 = 0,
+
+ /// Offset relative to the start address of the `segment`.
offset: u32 = 0,
- addend: ?i32 = null,
- index: u32,
pub fn deinit(self: *ExternSymbol, allocator: *Allocator) void {
- if (self.name) |*name| {
+ if (self.name) |name| {
allocator.free(name);
}
}
@@ -77,12 +79,6 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {
size += 1;
try leb.writeILEB128(writer, symbol.offset);
-
- if (symbol.addend) |addend| {
- size += 1;
- try leb.writeILEB128(writer, addend);
- }
-
size += 2;
}
@@ -110,12 +106,6 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
try leb.writeILEB128(writer, symbol.offset);
-
- if (symbol.addend) |addend| {
- try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
- try leb.writeILEB128(writer, addend);
- }
-
try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
try writer.writeByte(macho.BIND_OPCODE_DONE);
}
@@ -129,12 +119,6 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {
for (symbols) |symbol| {
size += 1;
try leb.writeILEB128(writer, symbol.offset);
-
- if (symbol.addend) |addend| {
- size += 1;
- try leb.writeILEB128(writer, addend);
- }
-
size += 1;
if (symbol.dylib_ordinal > 15) {
try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
@@ -156,11 +140,6 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
try leb.writeILEB128(writer, symbol.offset);
- if (symbol.addend) |addend| {
- try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
- try leb.writeILEB128(writer, addend);
- }
-
if (symbol.dylib_ordinal > 15) {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
src/link/MachO.zig
@@ -159,19 +159,29 @@ last_text_block: ?*TextBlock = null,
/// prior to calling `generateSymbol`, and then immediately deallocated
/// rather than sitting in the global scope.
pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
-
+/// A list of all stub (extern decls) fixups required for this run of the linker.
+/// Warning, this is currently NOT thread-safe. See the TODO below.
+/// TODO Move this list inside `updateDecl` where it should be allocated
+/// prior to calling `generateSymbol`, and then immediately deallocated
+/// rather than sitting in the global scope.
stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
-pub const StubFixup = struct {
- symbol: u32,
- already_defined: bool,
+pub const PieFixup = struct {
+ /// Target address we wanted to address in absolute terms.
+ address: u64,
+ /// Where in the byte stream we should perform the fixup.
start: usize,
+ /// The length of the byte stream. For x86_64, this will be
+ /// variable. For aarch64, it will be fixed at 4 bytes.
len: usize,
};
-pub const PieFixup = struct {
- /// Target address we wanted to address in absolute terms.
- address: u64,
+pub const StubFixup = struct {
+ /// Id of extern (lazy) symbol.
+ symbol: u32,
+ /// Signals whether the symbol has already been declared before. If so,
+ /// then there is no need to rewrite the stub entry and related.
+ already_defined: bool,
/// Where in the byte stream we should perform the fixup.
start: usize,
/// The length of the byte stream. For x86_64, this will be
@@ -1030,13 +1040,20 @@ pub fn deinit(self: *MachO) void {
if (self.d_sym) |*ds| {
ds.deinit(self.base.allocator);
}
+ for (self.extern_lazy_symbols.items()) |*entry| {
+ entry.value.deinit(self.base.allocator);
+ }
+ self.extern_lazy_symbols.deinit(self.base.allocator);
+ for (self.extern_nonlazy_symbols.items()) |*entry| {
+ entry.value.deinit(self.base.allocator);
+ }
+ self.extern_nonlazy_symbols.deinit(self.base.allocator);
self.pie_fixups.deinit(self.base.allocator);
+ self.stub_fixups.deinit(self.base.allocator);
self.text_block_free_list.deinit(self.base.allocator);
self.offset_table.deinit(self.base.allocator);
self.offset_table_free_list.deinit(self.base.allocator);
self.string_table.deinit(self.base.allocator);
- self.extern_lazy_symbols.deinit(self.base.allocator);
- self.extern_nonlazy_symbols.deinit(self.base.allocator);
self.global_symbols.deinit(self.base.allocator);
self.global_symbol_free_list.deinit(self.base.allocator);
self.local_symbols.deinit(self.base.allocator);
@@ -2047,7 +2064,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{
.name = name,
.dylib_ordinal = 1, // TODO this is currently hardcoded.
- .index = index,
.segment = self.data_const_segment_cmd_index.?,
.offset = index * @sizeOf(u64),
});
@@ -2582,12 +2598,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
}
fn writeIndirectSymbolTable(self: *MachO) !void {
- const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const stubs = &text_seg.sections.items[self.stubs_section_index.?];
- const dc_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
- const got = &dc_seg.sections.items[self.data_got_section_index.?];
- const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
- const la = &data_seg.sections.items[self.la_symbol_ptr_section_index.?];
+ 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_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const got = &data_const_seg.sections.items[self.data_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 dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
dysymtab.nindirectsyms = 0;
@@ -2595,8 +2611,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
var off = dysymtab.indirectsymoff;
stubs.reserved1 = 0;
- for (self.extern_lazy_symbols.items()) |entry| {
- const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
+ for (self.extern_lazy_symbols.items()) |_, i| {
+ const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
mem.writeIntLittle(u32, &buf, symtab_idx);
try self.base.file.?.pwriteAll(&buf, off);
off += @sizeOf(u32);
@@ -2605,17 +2621,17 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
const base_id = @intCast(u32, self.extern_lazy_symbols.items().len);
got.reserved1 = base_id;
- for (self.extern_nonlazy_symbols.items()) |entry| {
- const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + base_id);
+ for (self.extern_nonlazy_symbols.items()) |_, i| {
+ const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
mem.writeIntLittle(u32, &buf, symtab_idx);
try self.base.file.?.pwriteAll(&buf, off);
off += @sizeOf(u32);
dysymtab.nindirectsyms += 1;
}
- la.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
- for (self.extern_lazy_symbols.items()) |entry| {
- const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
+ la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
+ for (self.extern_lazy_symbols.items()) |_, i| {
+ const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
mem.writeIntLittle(u32, &buf, symtab_idx);
try self.base.file.?.pwriteAll(&buf, off);
off += @sizeOf(u32);
src/codegen.zig
@@ -1865,19 +1865,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// If it doesn't, it will get autofreed when we clean up the extern symbol table.
const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});
const already_defined = macho_file.extern_lazy_symbols.contains(decl_name);
- const symbol: u32 = blk: {
- if (macho_file.extern_lazy_symbols.get(decl_name)) |sym| {
- self.bin_file.allocator.free(decl_name);
- break :blk sym.index;
- } else {
- const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
- try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
- .name = decl_name,
- .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
- .index = index,
- });
- break :blk index;
- }
+ const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index| blk: {
+ self.bin_file.allocator.free(decl_name);
+ break :blk @intCast(u32, index);
+ } else blk: {
+ const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
+ try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
+ .name = decl_name,
+ .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
+ });
+ break :blk index;
};
try macho_file.stub_fixups.append(self.bin_file.allocator, .{
.symbol = symbol,
test/stage2/aarch64.zig
@@ -199,4 +199,21 @@ pub fn addCases(ctx: *TestContext) !void {
"",
);
}
+
+ {
+ var case = ctx.exe("hello world linked to libc", macos_aarch64);
+
+ // TODO rewrite this test once we handle more int conversions and return args.
+ case.addCompareOutput(
+ \\extern "c" fn write(usize, usize, usize) void;
+ \\extern "c" fn exit(usize) noreturn;
+ \\
+ \\export fn _start() noreturn {
+ \\ write(1, @ptrToInt("Hello, World!\n"), 14);
+ \\ exit(0);
+ \\}
+ ,
+ "Hello, World!\n",
+ );
+ }
}