| ... | ... | @@ -283,7 +283,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 283 | 283 | try self.allocateStubsAndGotEntries(); |
| 284 | 284 | try self.writeStubHelperCommon(); |
| 285 | 285 | try self.resolveRelocsAndWriteSections(); |
| 286 | | // try self.flush(); |
| 286 | try self.flush(); |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | 289 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| ... | ... | @@ -386,7 +386,7 @@ fn mapAndUpdateSections( |
| 386 | 386 | .target_sect_id = target_sect_id, |
| 387 | 387 | .offset = @intCast(u32, offset), |
| 388 | 388 | }); |
| 389 | | log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ |
| 389 | log.warn("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ |
| 390 | 390 | object.name, |
| 391 | 391 | parseName(&source_sect.segname), |
| 392 | 392 | parseName(&source_sect.sectname), |
| ... | ... | @@ -596,7 +596,7 @@ fn updateMetadata(self: *Zld) !void { |
| 596 | 596 | }); |
| 597 | 597 | }, |
| 598 | 598 | else => { |
| 599 | | log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); |
| 599 | log.warn("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); |
| 600 | 600 | }, |
| 601 | 601 | } |
| 602 | 602 | } |
| ... | ... | @@ -620,7 +620,7 @@ fn updateMetadata(self: *Zld) !void { |
| 620 | 620 | |
| 621 | 621 | const segname = parseName(&source_sect.segname); |
| 622 | 622 | const sectname = parseName(&source_sect.sectname); |
| 623 | | log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); |
| 623 | log.warn("section '{s}/{s}' will be unmapped", .{ segname, sectname }); |
| 624 | 624 | try self.unhandled_sections.putNoClobber(self.allocator, .{ |
| 625 | 625 | .object_id = object_id, |
| 626 | 626 | .source_sect_id = source_sect_id, |
| ... | ... | @@ -964,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void { |
| 964 | 964 | const target_addr = target_sect.addr + target_mapping.offset; |
| 965 | 965 | const n_value = source_sym.inner.n_value - source_sect.addr + target_addr; |
| 966 | 966 | |
| 967 | | log.debug("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 967 | log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 968 | 968 | |
| 969 | 969 | // TODO there might be a more generic way of doing this. |
| 970 | 970 | var n_sect: u8 = 0; |
| ... | ... | @@ -1172,7 +1172,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { |
| 1172 | 1172 | var buf: [@sizeOf(u64)]u8 = undefined; |
| 1173 | 1173 | mem.writeIntLittle(u64, &buf, end); |
| 1174 | 1174 | const off = la_symbol_ptr.offset + index * @sizeOf(u64); |
| 1175 | | log.debug("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); |
| 1175 | log.warn("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); |
| 1176 | 1176 | try self.file.?.pwriteAll(&buf, off); |
| 1177 | 1177 | } |
| 1178 | 1178 | |
| ... | ... | @@ -1185,7 +1185,7 @@ fn writeStub(self: *Zld, index: u32) !void { |
| 1185 | 1185 | const stub_off = stubs.offset + index * stubs.reserved2; |
| 1186 | 1186 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 1187 | 1187 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| 1188 | | log.debug("writing stub at 0x{x}", .{stub_off}); |
| 1188 | log.warn("writing stub at 0x{x}", .{stub_off}); |
| 1189 | 1189 | var code = try self.allocator.alloc(u8, stubs.reserved2); |
| 1190 | 1190 | defer self.allocator.free(code); |
| 1191 | 1191 | switch (self.arch.?) { |
| ... | ... | @@ -1444,7 +1444,7 @@ fn resolveSymbols(self: *Zld) !void { |
| 1444 | 1444 | |
| 1445 | 1445 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1446 | 1446 | for (self.objects.items) |object, object_id| { |
| 1447 | | log.debug("\nresolving stubs and got entries from {s}", .{object.name}); |
| 1447 | log.warn("\nresolving stubs and got entries from {s}", .{object.name}); |
| 1448 | 1448 | |
| 1449 | 1449 | for (object.sections.items) |sect| { |
| 1450 | 1450 | const relocs = sect.relocs orelse continue; |
| ... | ... | @@ -1469,7 +1469,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1469 | 1469 | .local_index = if (is_import) 0 else reloc.target.symbol, |
| 1470 | 1470 | }); |
| 1471 | 1471 | |
| 1472 | | log.debug(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) }); |
| 1472 | log.warn(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) }); |
| 1473 | 1473 | }, |
| 1474 | 1474 | else => { |
| 1475 | 1475 | const sym = object.symtab.items[reloc.target.symbol]; |
| ... | ... | @@ -1486,7 +1486,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1486 | 1486 | const index = @intCast(u32, self.stubs.items().len); |
| 1487 | 1487 | try self.stubs.putNoClobber(self.allocator, name, index); |
| 1488 | 1488 | |
| 1489 | | log.debug(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) }); |
| 1489 | log.warn(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) }); |
| 1490 | 1490 | }, |
| 1491 | 1491 | } |
| 1492 | 1492 | } |
| ... | ... | @@ -1504,7 +1504,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1504 | 1504 | .local_index = 0, |
| 1505 | 1505 | }); |
| 1506 | 1506 | |
| 1507 | | log.debug(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")}); |
| 1507 | log.warn(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")}); |
| 1508 | 1508 | } |
| 1509 | 1509 | |
| 1510 | 1510 | fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| ... | ... | @@ -1520,7 +1520,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1520 | 1520 | .object_id = @intCast(u16, object_id), |
| 1521 | 1521 | .source_sect_id = @intCast(u16, source_sect_id), |
| 1522 | 1522 | }) orelse { |
| 1523 | | log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname }); |
| 1523 | log.warn("no mapping for {s},{s}; skipping", .{ segname, sectname }); |
| 1524 | 1524 | continue; |
| 1525 | 1525 | }; |
| 1526 | 1526 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; |
| ... | ... | @@ -2128,6 +2128,7 @@ fn flush(self: *Zld) !void { |
| 2128 | 2128 | try self.file.?.pwriteAll(buffer, sect.offset); |
| 2129 | 2129 | } |
| 2130 | 2130 | |
| 2131 | try self.writeGotEntries(); |
| 2131 | 2132 | try self.setEntryPoint(); |
| 2132 | 2133 | try self.writeRebaseInfoTable(); |
| 2133 | 2134 | try self.writeBindInfoTable(); |
| ... | ... | @@ -2143,7 +2144,8 @@ fn flush(self: *Zld) !void { |
| 2143 | 2144 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 2144 | 2145 | } |
| 2145 | 2146 | |
| 2146 | | try self.writeDebugInfo(); |
| 2147 | // try self.writeDebugInfo(); |
| 2148 | try self.populateStringTable(); |
| 2147 | 2149 | try self.writeSymbolTable(); |
| 2148 | 2150 | try self.writeDynamicSymbolTable(); |
| 2149 | 2151 | try self.writeStringTable(); |
| ... | ... | @@ -2170,60 +2172,52 @@ fn flush(self: *Zld) !void { |
| 2170 | 2172 | } |
| 2171 | 2173 | } |
| 2172 | 2174 | |
| 2175 | fn writeGotEntries(self: *Zld) !void { |
| 2176 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2177 | const sect = seg.sections.items[self.got_section_index.?]; |
| 2178 | |
| 2179 | var buffer = try self.allocator.alloc(u8, self.got_entries.items().len * @sizeOf(u64)); |
| 2180 | defer self.allocator.free(buffer); |
| 2181 | |
| 2182 | var stream = std.io.fixedBufferStream(buffer); |
| 2183 | var writer = stream.writer(); |
| 2184 | |
| 2185 | for (self.got_entries.items()) |entry| { |
| 2186 | try writer.writeIntLittle(u64, entry.value.target_addr); |
| 2187 | } |
| 2188 | |
| 2189 | log.warn("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len }); |
| 2190 | |
| 2191 | try self.file.?.pwriteAll(buffer, sect.offset); |
| 2192 | } |
| 2193 | |
| 2173 | 2194 | fn setEntryPoint(self: *Zld) !void { |
| 2174 | 2195 | // TODO we should respect the -entry flag passed in by the user to set a custom |
| 2175 | 2196 | // entrypoint. For now, assume default of `_main`. |
| 2176 | 2197 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2177 | 2198 | const text = seg.sections.items[self.text_section_index.?]; |
| 2178 | | const entry_syms = self.locals.get("_main") orelse return error.MissingMainEntrypoint; |
| 2179 | | |
| 2180 | | var entry_sym: ?macho.nlist_64 = null; |
| 2181 | | for (entry_syms.items) |es| { |
| 2182 | | switch (es.tt) { |
| 2183 | | .Global => { |
| 2184 | | entry_sym = es.inner; |
| 2185 | | break; |
| 2186 | | }, |
| 2187 | | .WeakGlobal => { |
| 2188 | | entry_sym = es.inner; |
| 2189 | | }, |
| 2190 | | .Local => {}, |
| 2191 | | } |
| 2192 | | } |
| 2193 | | if (entry_sym == null) { |
| 2194 | | log.err("no (weak) global definition of _main found", .{}); |
| 2195 | | return error.MissingMainEntrypoint; |
| 2196 | | } |
| 2197 | | |
| 2198 | | const name = try self.allocator.dupe(u8, "_main"); |
| 2199 | | try self.exports.putNoClobber(self.allocator, name, .{ |
| 2200 | | .n_strx = entry_sym.?.n_strx, |
| 2201 | | .n_value = entry_sym.?.n_value, |
| 2202 | | .n_type = macho.N_SECT | macho.N_EXT, |
| 2203 | | .n_desc = entry_sym.?.n_desc, |
| 2204 | | .n_sect = entry_sym.?.n_sect, |
| 2205 | | }); |
| 2206 | | |
| 2199 | const entry_sym = self.symtab.get("_main") orelse return error.MissingMainEntrypoint; |
| 2207 | 2200 | const ec = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 2208 | | ec.entryoff = @intCast(u32, entry_sym.?.n_value - seg.inner.vmaddr); |
| 2201 | ec.entryoff = @intCast(u32, entry_sym.inner.n_value - seg.inner.vmaddr); |
| 2209 | 2202 | } |
| 2210 | 2203 | |
| 2211 | 2204 | fn writeRebaseInfoTable(self: *Zld) !void { |
| 2212 | 2205 | var pointers = std.ArrayList(Pointer).init(self.allocator); |
| 2213 | 2206 | defer pointers.deinit(); |
| 2214 | 2207 | |
| 2215 | | try pointers.ensureCapacity(pointers.items.len + self.local_rebases.items.len); |
| 2208 | try pointers.ensureCapacity(self.local_rebases.items.len); |
| 2216 | 2209 | pointers.appendSliceAssumeCapacity(self.local_rebases.items); |
| 2217 | 2210 | |
| 2218 | 2211 | if (self.got_section_index) |idx| { |
| 2219 | 2212 | // TODO this should be cleaned up! |
| 2220 | | try pointers.ensureCapacity(pointers.items.len + self.nonlazy_pointers.items().len); |
| 2221 | 2213 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2222 | 2214 | const sect = seg.sections.items[idx]; |
| 2223 | 2215 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2224 | 2216 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2225 | | const index_offset = @intCast(u32, self.nonlazy_imports.items().len); |
| 2226 | | for (self.nonlazy_pointers.items()) |entry| { |
| 2217 | const index_offset = @intCast(u32, self.got_entries.items().len); |
| 2218 | |
| 2219 | try pointers.ensureCapacity(pointers.items.len + self.got_entries.items().len); |
| 2220 | for (self.got_entries.items()) |entry| { |
| 2227 | 2221 | const index = index_offset + entry.value.index; |
| 2228 | 2222 | pointers.appendAssumeCapacity(.{ |
| 2229 | 2223 | .offset = base_offset + index * @sizeOf(u64), |
| ... | ... | @@ -2269,14 +2263,15 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2269 | 2263 | } |
| 2270 | 2264 | |
| 2271 | 2265 | if (self.la_symbol_ptr_section_index) |idx| { |
| 2272 | | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); |
| 2273 | 2266 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2274 | 2267 | const sect = seg.sections.items[idx]; |
| 2275 | 2268 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2276 | 2269 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 2277 | | for (self.lazy_imports.items()) |entry| { |
| 2270 | |
| 2271 | try pointers.ensureCapacity(pointers.items.len + self.stubs.items().len); |
| 2272 | for (self.stubs.items()) |entry| { |
| 2278 | 2273 | pointers.appendAssumeCapacity(.{ |
| 2279 | | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2274 | .offset = base_offset + entry.value * @sizeOf(u64), |
| 2280 | 2275 | .segment_id = segment_id, |
| 2281 | 2276 | }); |
| 2282 | 2277 | } |
| ... | ... | @@ -2297,7 +2292,7 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2297 | 2292 | dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64))); |
| 2298 | 2293 | seg.inner.filesize += dyld_info.rebase_size; |
| 2299 | 2294 | |
| 2300 | | log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); |
| 2295 | log.warn("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); |
| 2301 | 2296 | |
| 2302 | 2297 | try self.file.?.pwriteAll(buffer, dyld_info.rebase_off); |
| 2303 | 2298 | } |
| ... | ... | @@ -2307,16 +2302,23 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2307 | 2302 | defer pointers.deinit(); |
| 2308 | 2303 | |
| 2309 | 2304 | if (self.got_section_index) |idx| { |
| 2310 | | try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len); |
| 2311 | 2305 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2312 | 2306 | const sect = seg.sections.items[idx]; |
| 2313 | 2307 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2314 | 2308 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2315 | | for (self.nonlazy_imports.items()) |entry| { |
| 2309 | |
| 2310 | try pointers.ensureCapacity(pointers.items.len + self.got_entries.items().len); |
| 2311 | for (self.got_entries.items()) |entry| { |
| 2312 | const dylib_ordinal = dylib_ordinal: { |
| 2313 | const sym = self.symtab.get(entry.key) orelse continue; // local indirection |
| 2314 | if (sym.tag != .Import) continue; // local indirection |
| 2315 | break :dylib_ordinal sym.file.? + 1; |
| 2316 | }; |
| 2317 | |
| 2316 | 2318 | pointers.appendAssumeCapacity(.{ |
| 2317 | 2319 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2318 | 2320 | .segment_id = segment_id, |
| 2319 | | .dylib_ordinal = entry.value.dylib_ordinal, |
| 2321 | .dylib_ordinal = dylib_ordinal, |
| 2320 | 2322 | .name = entry.key, |
| 2321 | 2323 | }); |
| 2322 | 2324 | } |
| ... | ... | @@ -2327,10 +2329,14 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2327 | 2329 | const sect = seg.sections.items[idx]; |
| 2328 | 2330 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2329 | 2331 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 2332 | |
| 2333 | const sym = self.symtab.get("__tlv_bootstrap") orelse unreachable; |
| 2334 | const dylib_ordinal = sym.file.? + 1; |
| 2335 | |
| 2330 | 2336 | try pointers.append(.{ |
| 2331 | | .offset = base_offset + self.tlv_bootstrap.?.index * @sizeOf(u64), |
| 2337 | .offset = base_offset, |
| 2332 | 2338 | .segment_id = segment_id, |
| 2333 | | .dylib_ordinal = self.tlv_bootstrap.?.dylib_ordinal, |
| 2339 | .dylib_ordinal = dylib_ordinal, |
| 2334 | 2340 | .name = "__tlv_bootstrap", |
| 2335 | 2341 | }); |
| 2336 | 2342 | } |
| ... | ... | @@ -2348,7 +2354,7 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2348 | 2354 | dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); |
| 2349 | 2355 | seg.inner.filesize += dyld_info.bind_size; |
| 2350 | 2356 | |
| 2351 | | log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); |
| 2357 | log.warn("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); |
| 2352 | 2358 | |
| 2353 | 2359 | try self.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 2354 | 2360 | } |
| ... | ... | @@ -2356,18 +2362,26 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2356 | 2362 | fn writeLazyBindInfoTable(self: *Zld) !void { |
| 2357 | 2363 | var pointers = std.ArrayList(Pointer).init(self.allocator); |
| 2358 | 2364 | defer pointers.deinit(); |
| 2359 | | try pointers.ensureCapacity(self.lazy_imports.items().len); |
| 2360 | 2365 | |
| 2361 | 2366 | if (self.la_symbol_ptr_section_index) |idx| { |
| 2362 | 2367 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2363 | 2368 | const sect = seg.sections.items[idx]; |
| 2364 | 2369 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2365 | 2370 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 2366 | | for (self.lazy_imports.items()) |entry| { |
| 2371 | |
| 2372 | try pointers.ensureCapacity(self.stubs.items().len); |
| 2373 | |
| 2374 | for (self.stubs.items()) |entry| { |
| 2375 | const dylib_ordinal = dylib_ordinal: { |
| 2376 | const sym = self.symtab.get(entry.key) orelse unreachable; |
| 2377 | assert(sym.tag == .Import); |
| 2378 | break :dylib_ordinal sym.file.? + 1; |
| 2379 | }; |
| 2380 | |
| 2367 | 2381 | pointers.appendAssumeCapacity(.{ |
| 2368 | | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2382 | .offset = base_offset + entry.value * @sizeOf(u64), |
| 2369 | 2383 | .segment_id = segment_id, |
| 2370 | | .dylib_ordinal = entry.value.dylib_ordinal, |
| 2384 | .dylib_ordinal = dylib_ordinal, |
| 2371 | 2385 | .name = entry.key, |
| 2372 | 2386 | }); |
| 2373 | 2387 | } |
| ... | ... | @@ -2386,7 +2400,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void { |
| 2386 | 2400 | dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); |
| 2387 | 2401 | seg.inner.filesize += dyld_info.lazy_bind_size; |
| 2388 | 2402 | |
| 2389 | | log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); |
| 2403 | log.warn("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); |
| 2390 | 2404 | |
| 2391 | 2405 | try self.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 2392 | 2406 | try self.populateLazyBindOffsetsInStubHelper(buffer); |
| ... | ... | @@ -2437,7 +2451,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void { |
| 2437 | 2451 | else => {}, |
| 2438 | 2452 | } |
| 2439 | 2453 | } |
| 2440 | | assert(self.lazy_imports.items().len <= offsets.items.len); |
| 2454 | assert(self.stubs.items().len <= offsets.items.len); |
| 2441 | 2455 | |
| 2442 | 2456 | const stub_size: u4 = switch (self.arch.?) { |
| 2443 | 2457 | .x86_64 => 10, |
| ... | ... | @@ -2450,10 +2464,9 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void { |
| 2450 | 2464 | else => unreachable, |
| 2451 | 2465 | }; |
| 2452 | 2466 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2453 | | for (self.lazy_imports.items()) |entry| { |
| 2454 | | const symbol = entry.value; |
| 2455 | | const placeholder_off = self.stub_helper_stubs_start_off.? + symbol.index * stub_size + off; |
| 2456 | | mem.writeIntLittle(u32, &buf, offsets.items[symbol.index]); |
| 2467 | for (self.stubs.items()) |entry| { |
| 2468 | const placeholder_off = self.stub_helper_stubs_start_off.? + entry.value * stub_size + off; |
| 2469 | mem.writeIntLittle(u32, &buf, offsets.items[entry.value]); |
| 2457 | 2470 | try self.file.?.pwriteAll(&buf, placeholder_off); |
| 2458 | 2471 | } |
| 2459 | 2472 | } |
| ... | ... | @@ -2463,11 +2476,16 @@ fn writeExportInfo(self: *Zld) !void { |
| 2463 | 2476 | defer trie.deinit(); |
| 2464 | 2477 | |
| 2465 | 2478 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2466 | | for (self.exports.items()) |entry| { |
| 2479 | for (self.symtab.items()) |entry| { |
| 2480 | switch (entry.value.tag) { |
| 2481 | .Weak, .Strong => {}, |
| 2482 | else => continue, |
| 2483 | } |
| 2467 | 2484 | const name = entry.key; |
| 2468 | | const symbol = entry.value; |
| 2469 | | // TODO figure out if we should put all exports into the export trie |
| 2485 | const symbol = entry.value.inner; |
| 2486 | |
| 2470 | 2487 | assert(symbol.n_value >= text_segment.inner.vmaddr); |
| 2488 | |
| 2471 | 2489 | try trie.put(.{ |
| 2472 | 2490 | .name = name, |
| 2473 | 2491 | .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr, |
| ... | ... | @@ -2488,7 +2506,7 @@ fn writeExportInfo(self: *Zld) !void { |
| 2488 | 2506 | dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); |
| 2489 | 2507 | seg.inner.filesize += dyld_info.export_size; |
| 2490 | 2508 | |
| 2491 | | log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); |
| 2509 | log.warn("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); |
| 2492 | 2510 | |
| 2493 | 2511 | try self.file.?.pwriteAll(buffer, dyld_info.export_off); |
| 2494 | 2512 | } |
| ... | ... | @@ -2508,7 +2526,7 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2508 | 2526 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { |
| 2509 | 2527 | error.MissingDebugInfo => { |
| 2510 | 2528 | // TODO audit cases with missing debug info and audit our dwarf.zig module. |
| 2511 | | log.debug("invalid or missing debug info in {s}; skipping", .{object.name}); |
| 2529 | log.warn("invalid or missing debug info in {s}; skipping", .{object.name}); |
| 2512 | 2530 | continue; |
| 2513 | 2531 | }, |
| 2514 | 2532 | else => |e| return e, |
| ... | ... | @@ -2558,7 +2576,7 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2558 | 2576 | .n_value = mtime, |
| 2559 | 2577 | }); |
| 2560 | 2578 | } |
| 2561 | | log.debug("analyzing debug info in '{s}'", .{object.name}); |
| 2579 | log.warn("analyzing debug info in '{s}'", .{object.name}); |
| 2562 | 2580 | |
| 2563 | 2581 | for (object.symtab.items) |source_sym| { |
| 2564 | 2582 | const symname = object.getString(source_sym.n_strx); |
| ... | ... | @@ -2639,7 +2657,7 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2639 | 2657 | |
| 2640 | 2658 | const stabs_off = symtab.symoff; |
| 2641 | 2659 | const stabs_size = symtab.nsyms * @sizeOf(macho.nlist_64); |
| 2642 | | log.debug("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); |
| 2660 | log.warn("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); |
| 2643 | 2661 | try self.file.?.pwriteAll(mem.sliceAsBytes(stabs.items), stabs_off); |
| 2644 | 2662 | |
| 2645 | 2663 | linkedit.inner.filesize += stabs_size; |
| ... | ... | @@ -2649,66 +2667,56 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2649 | 2667 | dysymtab.nlocalsym = symtab.nsyms; |
| 2650 | 2668 | } |
| 2651 | 2669 | |
| 2670 | fn populateStringTable(self: *Zld) !void { |
| 2671 | for (self.symtab.items()) |*entry| { |
| 2672 | const n_strx = try self.makeString(entry.key); |
| 2673 | entry.value.inner.n_strx = n_strx; |
| 2674 | } |
| 2675 | } |
| 2676 | |
| 2652 | 2677 | fn writeSymbolTable(self: *Zld) !void { |
| 2653 | 2678 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2654 | 2679 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2655 | 2680 | |
| 2681 | // TODO figure out how to add locals |
| 2656 | 2682 | var locals = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2657 | 2683 | defer locals.deinit(); |
| 2658 | 2684 | |
| 2659 | | for (self.locals.items()) |entries| { |
| 2660 | | log.debug("'{s}': {} entries", .{ entries.key, entries.value.items.len }); |
| 2661 | | // var symbol: ?macho.nlist_64 = null; |
| 2662 | | for (entries.value.items) |entry| { |
| 2663 | | log.debug(" | {}", .{entry.inner}); |
| 2664 | | log.debug(" | {}", .{entry.tt}); |
| 2665 | | log.debug(" | {s}", .{self.objects.items[entry.object_id].name}); |
| 2666 | | try locals.append(entry.inner); |
| 2667 | | } |
| 2668 | | } |
| 2669 | | const nlocals = locals.items.len; |
| 2670 | | |
| 2671 | | const nexports = self.exports.items().len; |
| 2672 | 2685 | var exports = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2673 | 2686 | defer exports.deinit(); |
| 2674 | 2687 | |
| 2675 | | try exports.ensureCapacity(nexports); |
| 2676 | | for (self.exports.items()) |entry| { |
| 2677 | | exports.appendAssumeCapacity(entry.value); |
| 2678 | | } |
| 2679 | | |
| 2680 | | const has_tlv: bool = self.tlv_bootstrap != null; |
| 2681 | | |
| 2682 | | var nundefs = self.lazy_imports.items().len + self.nonlazy_imports.items().len; |
| 2683 | | if (has_tlv) nundefs += 1; |
| 2684 | | |
| 2685 | 2688 | var undefs = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2686 | 2689 | defer undefs.deinit(); |
| 2687 | 2690 | |
| 2688 | | try undefs.ensureCapacity(nundefs); |
| 2689 | | for (self.lazy_imports.items()) |entry| { |
| 2690 | | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2691 | | } |
| 2692 | | for (self.nonlazy_imports.items()) |entry| { |
| 2693 | | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2694 | | } |
| 2695 | | if (has_tlv) { |
| 2696 | | undefs.appendAssumeCapacity(self.tlv_bootstrap.?.symbol); |
| 2691 | for (self.symtab.items()) |entry| { |
| 2692 | switch (entry.value.tag) { |
| 2693 | .Weak, .Strong => { |
| 2694 | try exports.append(entry.value.inner); |
| 2695 | }, |
| 2696 | .Import => { |
| 2697 | try undefs.append(entry.value.inner); |
| 2698 | }, |
| 2699 | else => unreachable, |
| 2700 | } |
| 2697 | 2701 | } |
| 2698 | 2702 | |
| 2703 | const nlocals = locals.items.len; |
| 2704 | const nexports = exports.items.len; |
| 2705 | const nundefs = undefs.items.len; |
| 2706 | |
| 2699 | 2707 | const locals_off = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); |
| 2700 | 2708 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| 2701 | | log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); |
| 2709 | log.warn("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); |
| 2702 | 2710 | try self.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); |
| 2703 | 2711 | |
| 2704 | 2712 | const exports_off = locals_off + locals_size; |
| 2705 | 2713 | const exports_size = nexports * @sizeOf(macho.nlist_64); |
| 2706 | | log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); |
| 2714 | log.warn("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); |
| 2707 | 2715 | try self.file.?.pwriteAll(mem.sliceAsBytes(exports.items), exports_off); |
| 2708 | 2716 | |
| 2709 | 2717 | const undefs_off = exports_off + exports_size; |
| 2710 | 2718 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); |
| 2711 | | log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 2719 | log.warn("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 2712 | 2720 | try self.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off); |
| 2713 | 2721 | |
| 2714 | 2722 | symtab.nsyms += @intCast(u32, nlocals + nexports + nundefs); |
| ... | ... | @@ -2733,44 +2741,45 @@ fn writeDynamicSymbolTable(self: *Zld) !void { |
| 2733 | 2741 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2734 | 2742 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 2735 | 2743 | |
| 2736 | | const lazy = self.lazy_imports.items(); |
| 2737 | | const nonlazy = self.nonlazy_imports.items(); |
| 2738 | | const got_locals = self.nonlazy_pointers.items(); |
| 2744 | const nstubs = @intCast(u32, self.stubs.items().len); |
| 2745 | const ngot_entries = @intCast(u32, self.got_entries.items().len); |
| 2746 | |
| 2739 | 2747 | dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 2740 | | dysymtab.nindirectsyms = @intCast(u32, lazy.len * 2 + nonlazy.len + got_locals.len); |
| 2748 | dysymtab.nindirectsyms = nstubs * 2 + ngot_entries; |
| 2749 | |
| 2741 | 2750 | const needed_size = dysymtab.nindirectsyms * @sizeOf(u32); |
| 2742 | 2751 | seg.inner.filesize += needed_size; |
| 2743 | 2752 | |
| 2744 | | log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ |
| 2753 | log.warn("writing indirect symbol table from 0x{x} to 0x{x}", .{ |
| 2745 | 2754 | dysymtab.indirectsymoff, |
| 2746 | 2755 | dysymtab.indirectsymoff + needed_size, |
| 2747 | 2756 | }); |
| 2748 | 2757 | |
| 2749 | 2758 | var buf = try self.allocator.alloc(u8, needed_size); |
| 2750 | 2759 | defer self.allocator.free(buf); |
| 2760 | |
| 2751 | 2761 | var stream = std.io.fixedBufferStream(buf); |
| 2752 | 2762 | var writer = stream.writer(); |
| 2753 | 2763 | |
| 2754 | 2764 | stubs.reserved1 = 0; |
| 2755 | | for (lazy) |_, i| { |
| 2756 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2765 | for (self.stubs.items()) |entry| { |
| 2766 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value); |
| 2757 | 2767 | try writer.writeIntLittle(u32, symtab_idx); |
| 2758 | 2768 | } |
| 2759 | 2769 | |
| 2760 | | const base_id = @intCast(u32, lazy.len); |
| 2761 | | got.reserved1 = base_id; |
| 2762 | | for (nonlazy) |_, i| { |
| 2763 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); |
| 2764 | | try writer.writeIntLittle(u32, symtab_idx); |
| 2765 | | } |
| 2766 | | // TODO there should be one common set of GOT entries. |
| 2767 | | for (got_locals) |_| { |
| 2768 | | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2770 | got.reserved1 = nstubs; |
| 2771 | for (self.got_entries.items()) |entry| { |
| 2772 | if (entry.value.tag == .import) { |
| 2773 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + nstubs); |
| 2774 | try writer.writeIntLittle(u32, symtab_idx); |
| 2775 | } else { |
| 2776 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2777 | } |
| 2769 | 2778 | } |
| 2770 | 2779 | |
| 2771 | | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len) + @intCast(u32, got_locals.len); |
| 2772 | | for (lazy) |_, i| { |
| 2773 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2780 | la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; |
| 2781 | for (self.stubs.items()) |entry| { |
| 2782 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value); |
| 2774 | 2783 | try writer.writeIntLittle(u32, symtab_idx); |
| 2775 | 2784 | } |
| 2776 | 2785 | |
| ... | ... | @@ -2784,7 +2793,7 @@ fn writeStringTable(self: *Zld) !void { |
| 2784 | 2793 | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); |
| 2785 | 2794 | seg.inner.filesize += symtab.strsize; |
| 2786 | 2795 | |
| 2787 | | log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 2796 | log.warn("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 2788 | 2797 | |
| 2789 | 2798 | try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); |
| 2790 | 2799 | |
| ... | ... | @@ -2830,7 +2839,7 @@ fn writeDataInCode(self: *Zld) !void { |
| 2830 | 2839 | dice_cmd.datasize = datasize; |
| 2831 | 2840 | seg.inner.filesize += datasize; |
| 2832 | 2841 | |
| 2833 | | log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); |
| 2842 | log.warn("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); |
| 2834 | 2843 | |
| 2835 | 2844 | try self.file.?.pwriteAll(buf.items, fileoff); |
| 2836 | 2845 | } |
| ... | ... | @@ -2851,7 +2860,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { |
| 2851 | 2860 | seg.inner.filesize += needed_size; |
| 2852 | 2861 | seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); |
| 2853 | 2862 | |
| 2854 | | log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); |
| 2863 | log.warn("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); |
| 2855 | 2864 | |
| 2856 | 2865 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 2857 | 2866 | // except for code signature data. |
| ... | ... | @@ -2877,7 +2886,7 @@ fn writeCodeSignature(self: *Zld) !void { |
| 2877 | 2886 | var stream = std.io.fixedBufferStream(buffer); |
| 2878 | 2887 | try code_sig.write(stream.writer()); |
| 2879 | 2888 | |
| 2880 | | log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); |
| 2889 | log.warn("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); |
| 2881 | 2890 | try self.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); |
| 2882 | 2891 | } |
| 2883 | 2892 | |
| ... | ... | @@ -2895,7 +2904,7 @@ fn writeLoadCommands(self: *Zld) !void { |
| 2895 | 2904 | } |
| 2896 | 2905 | |
| 2897 | 2906 | const off = @sizeOf(macho.mach_header_64); |
| 2898 | | log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); |
| 2907 | log.warn("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); |
| 2899 | 2908 | try self.file.?.pwriteAll(buffer, off); |
| 2900 | 2909 | } |
| 2901 | 2910 | |
| ... | ... | @@ -2933,7 +2942,7 @@ fn writeHeader(self: *Zld) !void { |
| 2933 | 2942 | for (self.load_commands.items) |cmd| { |
| 2934 | 2943 | header.sizeofcmds += cmd.cmdsize(); |
| 2935 | 2944 | } |
| 2936 | | log.debug("writing Mach-O header {}", .{header}); |
| 2945 | log.warn("writing Mach-O header {}", .{header}); |
| 2937 | 2946 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); |
| 2938 | 2947 | } |
| 2939 | 2948 | |
| ... | ... | @@ -2947,7 +2956,7 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 { |
| 2947 | 2956 | fn makeString(self: *Zld, bytes: []const u8) !u32 { |
| 2948 | 2957 | try self.strtab.ensureCapacity(self.allocator, self.strtab.items.len + bytes.len + 1); |
| 2949 | 2958 | const offset = @intCast(u32, self.strtab.items.len); |
| 2950 | | log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); |
| 2959 | log.warn("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); |
| 2951 | 2960 | self.strtab.appendSliceAssumeCapacity(bytes); |
| 2952 | 2961 | self.strtab.appendAssumeCapacity(0); |
| 2953 | 2962 | return offset; |
| ... | ... | @@ -2963,11 +2972,6 @@ pub fn parseName(name: *const [16]u8) []const u8 { |
| 2963 | 2972 | return name[0..len]; |
| 2964 | 2973 | } |
| 2965 | 2974 | |
| 2966 | | fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { |
| 2967 | | const group_decode = @truncate(u5, inst[3]); |
| 2968 | | return ((group_decode >> 2) == 4); |
| 2969 | | } |
| 2970 | | |
| 2971 | 2975 | fn printDebug(self: Zld) void { |
| 2972 | 2976 | log.warn("symtab", .{}); |
| 2973 | 2977 | for (self.symtab.items()) |entry| { |