authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-09 20:38:55+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-13 23:55:18+01:00
log7d40aaad2b514703995458909b315f222543c4cd
tree063c91b13265579d66a15c268e4546209fd79247
parentb86d0e488b9dfc7d943da86a34998360e24da225

macho: document more code + add test case


4 files changed, 71 insertions(+), 62 deletions(-)

src/codegen.zig+10-13
......@@ -1865,19 +1865,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18651865 // If it doesn't, it will get autofreed when we clean up the extern symbol table.
18661866 const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});
18671867 const already_defined = macho_file.extern_lazy_symbols.contains(decl_name);
1868 const symbol: u32 = blk: {
1869 if (macho_file.extern_lazy_symbols.get(decl_name)) |sym| {
1870 self.bin_file.allocator.free(decl_name);
1871 break :blk sym.index;
1872 } else {
1873 const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
1874 try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
1875 .name = decl_name,
1876 .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
1877 .index = index,
1878 });
1879 break :blk index;
1880 }
1868 const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index| blk: {
1869 self.bin_file.allocator.free(decl_name);
1870 break :blk @intCast(u32, index);
1871 } else blk: {
1872 const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
1873 try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
1874 .name = decl_name,
1875 .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
1876 });
1877 break :blk index;
18811878 };
18821879 try macho_file.stub_fixups.append(self.bin_file.allocator, .{
18831880 .symbol = symbol,
src/link/MachO.zig+39-23
......@@ -159,19 +159,29 @@ last_text_block: ?*TextBlock = null,
159159/// prior to calling `generateSymbol`, and then immediately deallocated
160160/// rather than sitting in the global scope.
161161pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
162
162/// A list of all stub (extern decls) fixups required for this run of the linker.
163/// Warning, this is currently NOT thread-safe. See the TODO below.
164/// TODO Move this list inside `updateDecl` where it should be allocated
165/// prior to calling `generateSymbol`, and then immediately deallocated
166/// rather than sitting in the global scope.
163167stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
164168
165pub const StubFixup = struct {
166 symbol: u32,
167 already_defined: bool,
169pub const PieFixup = struct {
170 /// Target address we wanted to address in absolute terms.
171 address: u64,
172 /// Where in the byte stream we should perform the fixup.
168173 start: usize,
174 /// The length of the byte stream. For x86_64, this will be
175 /// variable. For aarch64, it will be fixed at 4 bytes.
169176 len: usize,
170177};
171178
172pub const PieFixup = struct {
173 /// Target address we wanted to address in absolute terms.
174 address: u64,
179pub const StubFixup = struct {
180 /// Id of extern (lazy) symbol.
181 symbol: u32,
182 /// Signals whether the symbol has already been declared before. If so,
183 /// then there is no need to rewrite the stub entry and related.
184 already_defined: bool,
175185 /// Where in the byte stream we should perform the fixup.
176186 start: usize,
177187 /// The length of the byte stream. For x86_64, this will be
......@@ -1030,13 +1040,20 @@ pub fn deinit(self: *MachO) void {
10301040 if (self.d_sym) |*ds| {
10311041 ds.deinit(self.base.allocator);
10321042 }
1043 for (self.extern_lazy_symbols.items()) |*entry| {
1044 entry.value.deinit(self.base.allocator);
1045 }
1046 self.extern_lazy_symbols.deinit(self.base.allocator);
1047 for (self.extern_nonlazy_symbols.items()) |*entry| {
1048 entry.value.deinit(self.base.allocator);
1049 }
1050 self.extern_nonlazy_symbols.deinit(self.base.allocator);
10331051 self.pie_fixups.deinit(self.base.allocator);
1052 self.stub_fixups.deinit(self.base.allocator);
10341053 self.text_block_free_list.deinit(self.base.allocator);
10351054 self.offset_table.deinit(self.base.allocator);
10361055 self.offset_table_free_list.deinit(self.base.allocator);
10371056 self.string_table.deinit(self.base.allocator);
1038 self.extern_lazy_symbols.deinit(self.base.allocator);
1039 self.extern_nonlazy_symbols.deinit(self.base.allocator);
10401057 self.global_symbols.deinit(self.base.allocator);
10411058 self.global_symbol_free_list.deinit(self.base.allocator);
10421059 self.local_symbols.deinit(self.base.allocator);
......@@ -2047,7 +2064,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
20472064 try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{
20482065 .name = name,
20492066 .dylib_ordinal = 1, // TODO this is currently hardcoded.
2050 .index = index,
20512067 .segment = self.data_const_segment_cmd_index.?,
20522068 .offset = index * @sizeOf(u64),
20532069 });
......@@ -2582,12 +2598,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
25822598}
25832599
25842600fn writeIndirectSymbolTable(self: *MachO) !void {
2585 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2586 const stubs = &text_seg.sections.items[self.stubs_section_index.?];
2587 const dc_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2588 const got = &dc_seg.sections.items[self.data_got_section_index.?];
2589 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2590 const la = &data_seg.sections.items[self.la_symbol_ptr_section_index.?];
2601 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2602 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
2603 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2604 const got = &data_const_seg.sections.items[self.data_got_section_index.?];
2605 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2606 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
25912607 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
25922608 dysymtab.nindirectsyms = 0;
25932609
......@@ -2595,8 +2611,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
25952611 var off = dysymtab.indirectsymoff;
25962612
25972613 stubs.reserved1 = 0;
2598 for (self.extern_lazy_symbols.items()) |entry| {
2599 const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
2614 for (self.extern_lazy_symbols.items()) |_, i| {
2615 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
26002616 mem.writeIntLittle(u32, &buf, symtab_idx);
26012617 try self.base.file.?.pwriteAll(&buf, off);
26022618 off += @sizeOf(u32);
......@@ -2605,17 +2621,17 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
26052621
26062622 const base_id = @intCast(u32, self.extern_lazy_symbols.items().len);
26072623 got.reserved1 = base_id;
2608 for (self.extern_nonlazy_symbols.items()) |entry| {
2609 const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + base_id);
2624 for (self.extern_nonlazy_symbols.items()) |_, i| {
2625 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
26102626 mem.writeIntLittle(u32, &buf, symtab_idx);
26112627 try self.base.file.?.pwriteAll(&buf, off);
26122628 off += @sizeOf(u32);
26132629 dysymtab.nindirectsyms += 1;
26142630 }
26152631
2616 la.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
2617 for (self.extern_lazy_symbols.items()) |entry| {
2618 const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
2632 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
2633 for (self.extern_lazy_symbols.items()) |_, i| {
2634 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
26192635 mem.writeIntLittle(u32, &buf, symtab_idx);
26202636 try self.base.file.?.pwriteAll(&buf, off);
26212637 off += @sizeOf(u32);
src/link/MachO/imports.zig+5-26
......@@ -20,13 +20,15 @@ pub const ExternSymbol = struct {
2020 /// dylibs.
2121 dylib_ordinal: i64 = 0,
2222
23 /// Id of the segment where this symbol is defined (will have its address
24 /// resolved).
2325 segment: u16 = 0,
26
27 /// Offset relative to the start address of the `segment`.
2428 offset: u32 = 0,
25 addend: ?i32 = null,
26 index: u32,
2729
2830 pub fn deinit(self: *ExternSymbol, allocator: *Allocator) void {
29 if (self.name) |*name| {
31 if (self.name) |name| {
3032 allocator.free(name);
3133 }
3234 }
......@@ -77,12 +79,6 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {
7779
7880 size += 1;
7981 try leb.writeILEB128(writer, symbol.offset);
80
81 if (symbol.addend) |addend| {
82 size += 1;
83 try leb.writeILEB128(writer, addend);
84 }
85
8682 size += 2;
8783 }
8884
......@@ -110,12 +106,6 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
110106
111107 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
112108 try leb.writeILEB128(writer, symbol.offset);
113
114 if (symbol.addend) |addend| {
115 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
116 try leb.writeILEB128(writer, addend);
117 }
118
119109 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
120110 try writer.writeByte(macho.BIND_OPCODE_DONE);
121111 }
......@@ -129,12 +119,6 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {
129119 for (symbols) |symbol| {
130120 size += 1;
131121 try leb.writeILEB128(writer, symbol.offset);
132
133 if (symbol.addend) |addend| {
134 size += 1;
135 try leb.writeILEB128(writer, addend);
136 }
137
138122 size += 1;
139123 if (symbol.dylib_ordinal > 15) {
140124 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
......@@ -156,11 +140,6 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void
156140 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
157141 try leb.writeILEB128(writer, symbol.offset);
158142
159 if (symbol.addend) |addend| {
160 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
161 try leb.writeILEB128(writer, addend);
162 }
163
164143 if (symbol.dylib_ordinal > 15) {
165144 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
166145 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
test/stage2/aarch64.zig+17
......@@ -199,4 +199,21 @@ pub fn addCases(ctx: *TestContext) !void {
199199 "",
200200 );
201201 }
202
203 {
204 var case = ctx.exe("hello world linked to libc", macos_aarch64);
205
206 // TODO rewrite this test once we handle more int conversions and return args.
207 case.addCompareOutput(
208 \\extern "c" fn write(usize, usize, usize) void;
209 \\extern "c" fn exit(usize) noreturn;
210 \\
211 \\export fn _start() noreturn {
212 \\ write(1, @ptrToInt("Hello, World!\n"), 14);
213 \\ exit(0);
214 \\}
215 ,
216 "Hello, World!\n",
217 );
218 }
202219}