authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-09 23:12:04+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-09 23:12:04+01:00
logd12c8db6421f28ca59c03b619c70126c6694b0d4
tree803f5500302741169e17e9e5a72a90f28fdb403a
parent6fb23542fe8503ba5c97bde950b1ebbe8f07f951
parent83bbc39c1582077cb5385536a04b7bf8bbffbf26
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18875 from ziglang/macho-zo-dwarf

macho: emit DWARF for ZigObject relocatable

9 files changed, 541 insertions(+), 283 deletions(-)

ci/x86_64-macos-release.sh+9
...@@ -25,6 +25,15 @@ cd $ZIGDIR...@@ -25,6 +25,15 @@ cd $ZIGDIR
25git fetch --unshallow || true25git fetch --unshallow || true
26git fetch --tags26git fetch --tags
2727
28# Test building from source without LLVM.
29git clean -fd
30rm -rf zig-out
31cc -o bootstrap bootstrap.c
32./bootstrap
33./zig2 build -Dno-lib
34# In order to run these behavior tests we need to move the `@cImport` ones to somewhere else.
35# ./zig-out/bin/zig test test/behavior.zig
36
28rm -rf build37rm -rf build
29mkdir build38mkdir build
30cd build39cd build
lib/std/builtin.zig+1-1
...@@ -764,7 +764,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr...@@ -764,7 +764,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
764 builtin.zig_backend == .stage2_arm or764 builtin.zig_backend == .stage2_arm or
765 builtin.zig_backend == .stage2_aarch64 or765 builtin.zig_backend == .stage2_aarch64 or
766 builtin.zig_backend == .stage2_x86 or766 builtin.zig_backend == .stage2_x86 or
767 (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) or767 (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
768 builtin.zig_backend == .stage2_riscv64 or768 builtin.zig_backend == .stage2_riscv64 or
769 builtin.zig_backend == .stage2_sparc64 or769 builtin.zig_backend == .stage2_sparc64 or
770 builtin.zig_backend == .stage2_spirv64)770 builtin.zig_backend == .stage2_spirv64)
src/Compilation.zig+2-2
...@@ -6278,7 +6278,7 @@ fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {...@@ -6278,7 +6278,7 @@ fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {
6278 }6278 }
6279 return switch (target_util.zigBackend(target, use_llvm)) {6279 return switch (target_util.zigBackend(target, use_llvm)) {
6280 .stage2_llvm => true,6280 .stage2_llvm => true,
6281 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,6281 .stage2_x86_64 => if (target.ofmt == .elf or target.ofmt == .macho) true else build_options.have_llvm,
6282 else => build_options.have_llvm,6282 else => build_options.have_llvm,
6283 };6283 };
6284}6284}
...@@ -6296,7 +6296,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {...@@ -6296,7 +6296,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
6296 }6296 }
6297 return switch (target_util.zigBackend(target, use_llvm)) {6297 return switch (target_util.zigBackend(target, use_llvm)) {
6298 .stage2_llvm => true,6298 .stage2_llvm => true,
6299 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,6299 .stage2_x86_64 => if (target.ofmt == .elf or target.ofmt == .macho) true else build_options.have_llvm,
6300 else => build_options.have_llvm,6300 else => build_options.have_llvm,
6301 };6301 };
6302}6302}
src/link/Dwarf.zig+200-82
...@@ -1282,10 +1282,17 @@ pub fn commitDeclState(...@@ -1282,10 +1282,17 @@ pub fn commitDeclState(
1282 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);1282 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1283 },1283 },
1284 .macho => {1284 .macho => {
1285 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1285 const macho_file = self.bin_file.cast(File.MachO).?;
1286 const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);1286 if (macho_file.base.isRelocatable()) {
1287 const file_pos = debug_line_sect.offset + src_fn.off;1287 const debug_line_sect = &macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
1288 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);1288 const file_pos = debug_line_sect.offset + src_fn.off;
1289 try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1290 } else {
1291 const d_sym = macho_file.getDebugSymbols().?;
1292 const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?);
1293 const file_pos = debug_line_sect.offset + src_fn.off;
1294 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
1295 }
1289 },1296 },
1290 .wasm => {1297 .wasm => {
1291 const wasm_file = self.bin_file.cast(File.Wasm).?;1298 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -1351,18 +1358,33 @@ pub fn commitDeclState(...@@ -1351,18 +1358,33 @@ pub fn commitDeclState(
1351 },1358 },
13521359
1353 .macho => {1360 .macho => {
1354 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1361 const macho_file = self.bin_file.cast(File.MachO).?;
1355 const sect_index = d_sym.debug_line_section_index.?;1362 if (macho_file.base.isRelocatable()) {
1356 try d_sym.growSection(sect_index, needed_size, true);1363 const sect_index = macho_file.debug_line_sect_index.?;
1357 const sect = d_sym.getSection(sect_index);1364 try macho_file.growSection(sect_index, needed_size);
1358 const file_pos = sect.offset + src_fn.off;1365 const sect = macho_file.sections.items(.header)[sect_index];
1359 try pwriteDbgLineNops(1366 const file_pos = sect.offset + src_fn.off;
1360 d_sym.file,1367 try pwriteDbgLineNops(
1361 file_pos,1368 macho_file.base.file.?,
1362 prev_padding_size,1369 file_pos,
1363 dbg_line_buffer.items,1370 prev_padding_size,
1364 next_padding_size,1371 dbg_line_buffer.items,
1365 );1372 next_padding_size,
1373 );
1374 } else {
1375 const d_sym = macho_file.getDebugSymbols().?;
1376 const sect_index = d_sym.debug_line_section_index.?;
1377 try d_sym.growSection(sect_index, needed_size, true, macho_file);
1378 const sect = d_sym.getSection(sect_index);
1379 const file_pos = sect.offset + src_fn.off;
1380 try pwriteDbgLineNops(
1381 d_sym.file,
1382 file_pos,
1383 prev_padding_size,
1384 dbg_line_buffer.items,
1385 next_padding_size,
1386 );
1387 }
1366 },1388 },
13671389
1368 .wasm => {1390 .wasm => {
...@@ -1459,16 +1481,21 @@ pub fn commitDeclState(...@@ -1459,16 +1481,21 @@ pub fn commitDeclState(
1459 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {1481 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
1460 switch (self.bin_file.tag) {1482 switch (self.bin_file.tag) {
1461 .macho => {1483 .macho => {
1462 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1484 const macho_file = self.bin_file.cast(File.MachO).?;
1463 try d_sym.relocs.append(d_sym.allocator, .{1485 if (macho_file.base.isRelocatable()) {
1464 .type = switch (reloc.type) {1486 // TODO
1465 .direct_load => .direct_load,1487 } else {
1466 .got_load => .got_load,1488 const d_sym = macho_file.getDebugSymbols().?;
1467 },1489 try d_sym.relocs.append(d_sym.allocator, .{
1468 .target = reloc.target,1490 .type = switch (reloc.type) {
1469 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,1491 .direct_load => .direct_load,
1470 .addend = 0,1492 .got_load => .got_load,
1471 });1493 },
1494 .target = reloc.target,
1495 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
1496 .addend = 0,
1497 });
1498 }
1472 },1499 },
1473 .elf => {}, // TODO1500 .elf => {}, // TODO
1474 else => unreachable,1501 else => unreachable,
...@@ -1511,10 +1538,17 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)...@@ -1511,10 +1538,17 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
1511 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);1538 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1512 },1539 },
1513 .macho => {1540 .macho => {
1514 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1541 const macho_file = self.bin_file.cast(File.MachO).?;
1515 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);1542 if (macho_file.base.isRelocatable()) {
1516 const file_pos = debug_info_sect.offset + atom.off;1543 const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
1517 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);1544 const file_pos = debug_info_sect.offset + atom.off;
1545 try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1546 } else {
1547 const d_sym = macho_file.getDebugSymbols().?;
1548 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
1549 const file_pos = debug_info_sect.offset + atom.off;
1550 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
1551 }
1518 },1552 },
1519 .wasm => {1553 .wasm => {
1520 const wasm_file = self.bin_file.cast(File.Wasm).?;1554 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -1597,19 +1631,35 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons...@@ -1597,19 +1631,35 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
1597 },1631 },
15981632
1599 .macho => {1633 .macho => {
1600 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1634 const macho_file = self.bin_file.cast(File.MachO).?;
1601 const sect_index = d_sym.debug_info_section_index.?;1635 if (macho_file.base.isRelocatable()) {
1602 try d_sym.growSection(sect_index, needed_size, true);1636 const sect_index = macho_file.debug_info_sect_index.?;
1603 const sect = d_sym.getSection(sect_index);1637 try macho_file.growSection(sect_index, needed_size);
1604 const file_pos = sect.offset + atom.off;1638 const sect = macho_file.sections.items(.header)[sect_index];
1605 try pwriteDbgInfoNops(1639 const file_pos = sect.offset + atom.off;
1606 d_sym.file,1640 try pwriteDbgInfoNops(
1607 file_pos,1641 macho_file.base.file.?,
1608 prev_padding_size,1642 file_pos,
1609 dbg_info_buf,1643 prev_padding_size,
1610 next_padding_size,1644 dbg_info_buf,
1611 trailing_zero,1645 next_padding_size,
1612 );1646 trailing_zero,
1647 );
1648 } else {
1649 const d_sym = macho_file.getDebugSymbols().?;
1650 const sect_index = d_sym.debug_info_section_index.?;
1651 try d_sym.growSection(sect_index, needed_size, true, macho_file);
1652 const sect = d_sym.getSection(sect_index);
1653 const file_pos = sect.offset + atom.off;
1654 try pwriteDbgInfoNops(
1655 d_sym.file,
1656 file_pos,
1657 prev_padding_size,
1658 dbg_info_buf,
1659 next_padding_size,
1660 trailing_zero,
1661 );
1662 }
1613 },1663 },
16141664
1615 .wasm => {1665 .wasm => {
...@@ -1670,10 +1720,17 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D...@@ -1670,10 +1720,17 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D
1670 try elf_file.base.file.?.pwriteAll(&data, file_pos);1720 try elf_file.base.file.?.pwriteAll(&data, file_pos);
1671 },1721 },
1672 .macho => {1722 .macho => {
1673 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1723 const macho_file = self.bin_file.cast(File.MachO).?;
1674 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);1724 if (macho_file.base.isRelocatable()) {
1675 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();1725 const sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
1676 try d_sym.file.pwriteAll(&data, file_pos);1726 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
1727 try macho_file.base.file.?.pwriteAll(&data, file_pos);
1728 } else {
1729 const d_sym = macho_file.getDebugSymbols().?;
1730 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
1731 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
1732 try d_sym.file.pwriteAll(&data, file_pos);
1733 }
1677 },1734 },
1678 .wasm => {1735 .wasm => {
1679 const wasm_file = self.bin_file.cast(File.Wasm).?;1736 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -1877,12 +1934,21 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {...@@ -1877,12 +1934,21 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
1877 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);1934 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1878 },1935 },
1879 .macho => {1936 .macho => {
1880 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1937 const macho_file = self.bin_file.cast(File.MachO).?;
1881 const sect_index = d_sym.debug_abbrev_section_index.?;1938 if (macho_file.base.isRelocatable()) {
1882 try d_sym.growSection(sect_index, needed_size, false);1939 const sect_index = macho_file.debug_abbrev_sect_index.?;
1883 const sect = d_sym.getSection(sect_index);1940 try macho_file.growSection(sect_index, needed_size);
1884 const file_pos = sect.offset + abbrev_offset;1941 const sect = macho_file.sections.items(.header)[sect_index];
1885 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);1942 const file_pos = sect.offset + abbrev_offset;
1943 try macho_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1944 } else {
1945 const d_sym = macho_file.getDebugSymbols().?;
1946 const sect_index = d_sym.debug_abbrev_section_index.?;
1947 try d_sym.growSection(sect_index, needed_size, false, macho_file);
1948 const sect = d_sym.getSection(sect_index);
1949 const file_pos = sect.offset + abbrev_offset;
1950 try d_sym.file.pwriteAll(&abbrev_buf, file_pos);
1951 }
1886 },1952 },
1887 .wasm => {1953 .wasm => {
1888 const wasm_file = self.bin_file.cast(File.Wasm).?;1954 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -1967,10 +2033,17 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64)...@@ -1967,10 +2033,17 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64)
1967 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);2033 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1968 },2034 },
1969 .macho => {2035 .macho => {
1970 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2036 const macho_file = self.bin_file.cast(File.MachO).?;
1971 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);2037 if (macho_file.base.isRelocatable()) {
1972 const file_pos = debug_info_sect.offset;2038 const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
1973 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);2039 const file_pos = debug_info_sect.offset;
2040 try pwriteDbgInfoNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
2041 } else {
2042 const d_sym = macho_file.getDebugSymbols().?;
2043 const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?);
2044 const file_pos = debug_info_sect.offset;
2045 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
2046 }
1974 },2047 },
1975 .wasm => {2048 .wasm => {
1976 const wasm_file = self.bin_file.cast(File.Wasm).?;2049 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -2292,12 +2365,21 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2292,12 +2365,21 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2292 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);2365 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2293 },2366 },
2294 .macho => {2367 .macho => {
2295 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2368 const macho_file = self.bin_file.cast(File.MachO).?;
2296 const sect_index = d_sym.debug_aranges_section_index.?;2369 if (macho_file.base.isRelocatable()) {
2297 try d_sym.growSection(sect_index, needed_size, false);2370 const sect_index = macho_file.debug_aranges_sect_index.?;
2298 const sect = d_sym.getSection(sect_index);2371 try macho_file.growSection(sect_index, needed_size);
2299 const file_pos = sect.offset;2372 const sect = macho_file.sections.items(.header)[sect_index];
2300 try d_sym.file.pwriteAll(di_buf.items, file_pos);2373 const file_pos = sect.offset;
2374 try macho_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2375 } else {
2376 const d_sym = macho_file.getDebugSymbols().?;
2377 const sect_index = d_sym.debug_aranges_section_index.?;
2378 try d_sym.growSection(sect_index, needed_size, false, macho_file);
2379 const sect = d_sym.getSection(sect_index);
2380 const file_pos = sect.offset;
2381 try d_sym.file.pwriteAll(di_buf.items, file_pos);
2382 }
2301 },2383 },
2302 .wasm => {2384 .wasm => {
2303 const wasm_file = self.bin_file.cast(File.Wasm).?;2385 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -2432,16 +2514,29 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2432,16 +2514,29 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2432 try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);2514 try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta);
2433 },2515 },
2434 .macho => {2516 .macho => {
2435 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2517 const macho_file = self.bin_file.cast(File.MachO).?;
2436 const sect_index = d_sym.debug_line_section_index.?;2518 if (macho_file.base.isRelocatable()) {
2437 const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);2519 const sect_index = macho_file.debug_line_sect_index.?;
2438 try d_sym.growSection(sect_index, needed_size, true);2520 const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta);
2439 const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;2521 try macho_file.growSection(sect_index, needed_size);
2522 const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off;
24402523
2441 const amt = try d_sym.file.preadAll(buffer, file_pos);2524 const amt = try macho_file.base.file.?.preadAll(buffer, file_pos);
2442 if (amt != buffer.len) return error.InputOutput;2525 if (amt != buffer.len) return error.InputOutput;
2526
2527 try macho_file.base.file.?.pwriteAll(buffer, file_pos + delta);
2528 } else {
2529 const d_sym = macho_file.getDebugSymbols().?;
2530 const sect_index = d_sym.debug_line_section_index.?;
2531 const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);
2532 try d_sym.growSection(sect_index, needed_size, true, macho_file);
2533 const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
2534
2535 const amt = try d_sym.file.preadAll(buffer, file_pos);
2536 if (amt != buffer.len) return error.InputOutput;
24432537
2444 try d_sym.file.pwriteAll(buffer, file_pos + delta);2538 try d_sym.file.pwriteAll(buffer, file_pos + delta);
2539 }
2445 },2540 },
2446 .wasm => {2541 .wasm => {
2447 const wasm_file = self.bin_file.cast(File.Wasm).?;2542 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -2487,10 +2582,17 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2487,10 +2582,17 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2487 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2582 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2488 },2583 },
2489 .macho => {2584 .macho => {
2490 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2585 const macho_file = self.bin_file.cast(File.MachO).?;
2491 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);2586 if (macho_file.base.isRelocatable()) {
2492 const file_pos = debug_line_sect.offset;2587 const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?];
2493 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);2588 const file_pos = debug_line_sect.offset;
2589 try pwriteDbgLineNops(macho_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2590 } else {
2591 const d_sym = macho_file.getDebugSymbols().?;
2592 const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?);
2593 const file_pos = debug_line_sect.offset;
2594 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
2595 }
2494 },2596 },
2495 .wasm => {2597 .wasm => {
2496 const wasm_file = self.bin_file.cast(File.Wasm).?;2598 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -2608,9 +2710,15 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2608,9 +2710,15 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2608 break :pos debug_info_sect.sh_offset;2710 break :pos debug_info_sect.sh_offset;
2609 },2711 },
2610 .macho => pos: {2712 .macho => pos: {
2611 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2713 const macho_file = self.bin_file.cast(File.MachO).?;
2612 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);2714 if (macho_file.base.isRelocatable()) {
2613 break :pos debug_info_sect.offset;2715 const debug_info_sect = &macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?];
2716 break :pos debug_info_sect.offset;
2717 } else {
2718 const d_sym = macho_file.getDebugSymbols().?;
2719 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
2720 break :pos debug_info_sect.offset;
2721 }
2614 },2722 },
2615 // for wasm, the offset is always 0 as we write to memory first2723 // for wasm, the offset is always 0 as we write to memory first
2616 .wasm => 0,2724 .wasm => 0,
...@@ -2628,8 +2736,13 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2628,8 +2736,13 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2628 try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);2736 try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2629 },2737 },
2630 .macho => {2738 .macho => {
2631 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2739 const macho_file = self.bin_file.cast(File.MachO).?;
2632 try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);2740 if (macho_file.base.isRelocatable()) {
2741 try macho_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2742 } else {
2743 const d_sym = macho_file.getDebugSymbols().?;
2744 try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
2745 }
2633 },2746 },
2634 .wasm => {2747 .wasm => {
2635 const wasm_file = self.bin_file.cast(File.Wasm).?;2748 const wasm_file = self.bin_file.cast(File.Wasm).?;
...@@ -2653,8 +2766,13 @@ fn addDIFile(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclIndex) !u28...@@ -2653,8 +2766,13 @@ fn addDIFile(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclIndex) !u28
2653 elf_file.markDirty(elf_file.debug_line_section_index.?);2766 elf_file.markDirty(elf_file.debug_line_section_index.?);
2654 },2767 },
2655 .macho => {2768 .macho => {
2656 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2769 const macho_file = self.bin_file.cast(File.MachO).?;
2657 d_sym.markDirty(d_sym.debug_line_section_index.?);2770 if (macho_file.base.isRelocatable()) {
2771 macho_file.markDirty(macho_file.debug_line_sect_index.?);
2772 } else {
2773 const d_sym = macho_file.getDebugSymbols().?;
2774 d_sym.markDirty(d_sym.debug_line_section_index.?, macho_file);
2775 }
2658 },2776 },
2659 .wasm => {},2777 .wasm => {},
2660 else => unreachable,2778 else => unreachable,
src/link/MachO.zig+135-45
...@@ -103,6 +103,14 @@ zig_const_sect_index: ?u8 = null,...@@ -103,6 +103,14 @@ zig_const_sect_index: ?u8 = null,
103zig_data_sect_index: ?u8 = null,103zig_data_sect_index: ?u8 = null,
104zig_bss_sect_index: ?u8 = null,104zig_bss_sect_index: ?u8 = null,
105105
106/// Tracked DWARF section headers that apply only when we emit relocatable.
107/// For executable and loadable images, DWARF is tracked directly by dSYM bundle object.
108debug_info_sect_index: ?u8 = null,
109debug_abbrev_sect_index: ?u8 = null,
110debug_str_sect_index: ?u8 = null,
111debug_aranges_sect_index: ?u8 = null,
112debug_line_sect_index: ?u8 = null,
113
106has_tlv: bool = false,114has_tlv: bool = false,
107binds_to_weak: bool = false,115binds_to_weak: bool = false,
108weak_defines: bool = false,116weak_defines: bool = false,
...@@ -255,44 +263,15 @@ pub fn createEmpty(...@@ -255,44 +263,15 @@ pub fn createEmpty(
255 )}),263 )}),
256 } });264 } });
257 self.zig_object = index;265 self.zig_object = index;
258 try self.getZigObject().?.init(self);266 const zo = self.getZigObject().?;
267 try zo.init(self);
268
259 try self.initMetadata(.{269 try self.initMetadata(.{
270 .emit = emit,
271 .zo = zo,
260 .symbol_count_hint = options.symbol_count_hint,272 .symbol_count_hint = options.symbol_count_hint,
261 .program_code_size_hint = options.program_code_size_hint,273 .program_code_size_hint = options.program_code_size_hint,
262 });274 });
263
264 switch (comp.config.debug_format) {
265 .strip => {},
266 .dwarf => if (!self.base.isRelocatable()) {
267 // Create dSYM bundle.
268 log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
269
270 const sep = fs.path.sep_str;
271 const d_sym_path = try std.fmt.allocPrint(
272 arena,
273 "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF",
274 .{emit.sub_path},
275 );
276
277 var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
278 defer d_sym_bundle.close();
279
280 const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
281 .truncate = false,
282 .read = true,
283 });
284
285 self.d_sym = .{
286 .allocator = gpa,
287 .dwarf = link.File.Dwarf.init(&self.base, .dwarf32),
288 .file = d_sym_file,
289 };
290 try self.d_sym.?.initMetadata(self);
291 } else {
292 @panic("TODO: implement generating and emitting __DWARF in .o file");
293 },
294 .code_view => unreachable,
295 }
296 }275 }
297 }276 }
298277
...@@ -978,7 +957,6 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {...@@ -978,7 +957,6 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
978957
979 const gpa = self.base.comp.gpa;958 const gpa = self.base.comp.gpa;
980 const file = try std.fs.cwd().openFile(path, .{});959 const file = try std.fs.cwd().openFile(path, .{});
981 errdefer file.close();
982 const handle = try self.addFileHandle(file);960 const handle = try self.addFileHandle(file);
983 const mtime: u64 = mtime: {961 const mtime: u64 = mtime: {
984 const stat = file.stat() catch break :mtime 0;962 const stat = file.stat() catch break :mtime 0;
...@@ -1015,7 +993,6 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar...@@ -1015,7 +993,6 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
1015 const gpa = self.base.comp.gpa;993 const gpa = self.base.comp.gpa;
1016994
1017 const file = try std.fs.cwd().openFile(lib.path, .{});995 const file = try std.fs.cwd().openFile(lib.path, .{});
1018 errdefer file.close();
1019 const handle = try self.addFileHandle(file);996 const handle = try self.addFileHandle(file);
1020997
1021 var archive = Archive{};998 var archive = Archive{};
...@@ -2015,6 +1992,11 @@ pub fn sortSections(self: *MachO) !void {...@@ -2015,6 +1992,11 @@ pub fn sortSections(self: *MachO) !void {
2015 &self.eh_frame_sect_index,1992 &self.eh_frame_sect_index,
2016 &self.unwind_info_sect_index,1993 &self.unwind_info_sect_index,
2017 &self.objc_stubs_sect_index,1994 &self.objc_stubs_sect_index,
1995 &self.debug_info_sect_index,
1996 &self.debug_str_sect_index,
1997 &self.debug_line_sect_index,
1998 &self.debug_abbrev_sect_index,
1999 &self.debug_info_sect_index,
2018 }) |maybe_index| {2000 }) |maybe_index| {
2019 if (maybe_index.*) |*index| {2001 if (maybe_index.*) |*index| {
2020 index.* = backlinks[index.*];2002 index.* = backlinks[index.*];
...@@ -2314,11 +2296,11 @@ fn allocateSections(self: *MachO) !void {...@@ -2314,11 +2296,11 @@ fn allocateSections(self: *MachO) !void {
2314 // Must move the entire section.2296 // Must move the entire section.
2315 const new_offset = self.findFreeSpace(existing_size, page_size);2297 const new_offset = self.findFreeSpace(existing_size, page_size);
23162298
2317 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{2299 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
2318 header.segName(),2300 header.segName(),
2319 header.sectName(),2301 header.sectName(),
2302 header.offset,
2320 new_offset,2303 new_offset,
2321 new_offset + existing_size,
2322 });2304 });
23232305
2324 try self.copyRangeAllZeroOut(header.offset, new_offset, existing_size);2306 try self.copyRangeAllZeroOut(header.offset, new_offset, existing_size);
...@@ -3152,7 +3134,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)...@@ -3152,7 +3134,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
31523134
3153pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void {3135pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void {
3154 if (self.llvm_object) |_| return;3136 if (self.llvm_object) |_| return;
3155 return self.getZigObject().?.updateDeclLineNumber(self, module, decl_index);3137 return self.getZigObject().?.updateDeclLineNumber(module, decl_index);
3156}3138}
31573139
3158pub fn updateExports(3140pub fn updateExports(
...@@ -3221,7 +3203,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {...@@ -3221,7 +3203,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
3221 for (self.sections.items(.header)) |header| {3203 for (self.sections.items(.header)) |header| {
3222 if (header.isZerofill()) continue;3204 if (header.isZerofill()) continue;
3223 const increased_size = padToIdeal(header.size);3205 const increased_size = padToIdeal(header.size);
3224 const test_end = header.offset + increased_size;3206 const test_end = header.offset +| increased_size;
3225 if (end > header.offset and start < test_end) {3207 if (end > header.offset and start < test_end) {
3226 return test_end;3208 return test_end;
3227 }3209 }
...@@ -3249,7 +3231,7 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {...@@ -3249,7 +3231,7 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
32493231
3250 for (self.sections.items(.header)) |header| {3232 for (self.sections.items(.header)) |header| {
3251 const increased_size = padToIdeal(header.size);3233 const increased_size = padToIdeal(header.size);
3252 const test_end = header.addr + increased_size;3234 const test_end = header.addr +| increased_size;
3253 if (end > header.addr and start < test_end) {3235 if (end > header.addr and start < test_end) {
3254 return test_end;3236 return test_end;
3255 }3237 }
...@@ -3266,27 +3248,39 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {...@@ -3266,27 +3248,39 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
3266 return null;3248 return null;
3267}3249}
32683250
3269fn allocatedSize(self: *MachO, start: u64) u64 {3251pub fn allocatedSize(self: *MachO, start: u64) u64 {
3270 if (start == 0) return 0;3252 if (start == 0) return 0;
3253
3271 var min_pos: u64 = std.math.maxInt(u64);3254 var min_pos: u64 = std.math.maxInt(u64);
3255
3272 for (self.sections.items(.header)) |header| {3256 for (self.sections.items(.header)) |header| {
3273 if (header.offset <= start) continue;3257 if (header.offset <= start) continue;
3274 if (header.offset < min_pos) min_pos = header.offset;3258 if (header.offset < min_pos) min_pos = header.offset;
3275 }3259 }
3260
3276 for (self.segments.items) |seg| {3261 for (self.segments.items) |seg| {
3277 if (seg.fileoff <= start) continue;3262 if (seg.fileoff <= start) continue;
3278 if (seg.fileoff < min_pos) min_pos = seg.fileoff;3263 if (seg.fileoff < min_pos) min_pos = seg.fileoff;
3279 }3264 }
3265
3280 return min_pos - start;3266 return min_pos - start;
3281}3267}
32823268
3283fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {3269pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
3284 if (start == 0) return 0;3270 if (start == 0) return 0;
3271
3285 var min_pos: u64 = std.math.maxInt(u64);3272 var min_pos: u64 = std.math.maxInt(u64);
3273
3274 for (self.sections.items(.header)) |header| {
3275 if (header.addr <= start) continue;
3276 if (header.addr < min_pos) min_pos = header.addr;
3277 }
3278
3286 for (self.segments.items) |seg| {3279 for (self.segments.items) |seg| {
3287 if (seg.vmaddr <= start) continue;3280 if (seg.vmaddr <= start) continue;
3288 if (seg.vmaddr < min_pos) min_pos = seg.vmaddr;3281 if (seg.vmaddr < min_pos) min_pos = seg.vmaddr;
3289 }3282 }
3283
3290 return min_pos - start;3284 return min_pos - start;
3291}3285}
32923286
...@@ -3325,6 +3319,8 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64...@@ -3325,6 +3319,8 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64
3325}3319}
33263320
3327const InitMetadataOptions = struct {3321const InitMetadataOptions = struct {
3322 emit: Compilation.Emit,
3323 zo: *ZigObject,
3328 symbol_count_hint: u64,3324 symbol_count_hint: u64,
3329 program_code_size_hint: u64,3325 program_code_size_hint: u64,
3330};3326};
...@@ -3393,6 +3389,31 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3393,6 +3389,31 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3393 .prot = macho.PROT.READ | macho.PROT.WRITE,3389 .prot = macho.PROT.READ | macho.PROT.WRITE,
3394 });3390 });
3395 }3391 }
3392
3393 if (options.zo.dwarf) |_| {
3394 // Create dSYM bundle.
3395 log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path});
3396
3397 const gpa = self.base.comp.gpa;
3398 const sep = fs.path.sep_str;
3399 const d_sym_path = try std.fmt.allocPrint(
3400 gpa,
3401 "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF",
3402 .{options.emit.sub_path},
3403 );
3404 defer gpa.free(d_sym_path);
3405
3406 var d_sym_bundle = try options.emit.directory.handle.makeOpenPath(d_sym_path, .{});
3407 defer d_sym_bundle.close();
3408
3409 const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{
3410 .truncate = false,
3411 .read = true,
3412 });
3413
3414 self.d_sym = .{ .allocator = gpa, .file = d_sym_file };
3415 try self.d_sym.?.initMetadata(self);
3416 }
3396 }3417 }
33973418
3398 const appendSect = struct {3419 const appendSect = struct {
...@@ -3470,6 +3491,44 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3470,6 +3491,44 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3470 appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);3491 appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);
3471 }3492 }
3472 }3493 }
3494
3495 if (self.base.isRelocatable() and options.zo.dwarf != null) {
3496 {
3497 self.debug_str_sect_index = try self.addSection("__DWARF", "__debug_str", .{
3498 .flags = macho.S_ATTR_DEBUG,
3499 });
3500 try allocSect(self, self.debug_str_sect_index.?, 200);
3501 }
3502
3503 {
3504 self.debug_info_sect_index = try self.addSection("__DWARF", "__debug_info", .{
3505 .flags = macho.S_ATTR_DEBUG,
3506 });
3507 try allocSect(self, self.debug_info_sect_index.?, 200);
3508 }
3509
3510 {
3511 self.debug_abbrev_sect_index = try self.addSection("__DWARF", "__debug_abbrev", .{
3512 .flags = macho.S_ATTR_DEBUG,
3513 });
3514 try allocSect(self, self.debug_abbrev_sect_index.?, 128);
3515 }
3516
3517 {
3518 self.debug_aranges_sect_index = try self.addSection("__DWARF", "__debug_aranges", .{
3519 .alignment = 4,
3520 .flags = macho.S_ATTR_DEBUG,
3521 });
3522 try allocSect(self, self.debug_aranges_sect_index.?, 160);
3523 }
3524
3525 {
3526 self.debug_line_sect_index = try self.addSection("__DWARF", "__debug_line", .{
3527 .flags = macho.S_ATTR_DEBUG,
3528 });
3529 try allocSect(self, self.debug_line_sect_index.?, 250);
3530 }
3531 }
3473}3532}
34743533
3475pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {3534pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
...@@ -3491,11 +3550,11 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3491,11 +3550,11 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
3491 const alignment = self.getPageSize();3550 const alignment = self.getPageSize();
3492 const new_offset = self.findFreeSpace(needed_size, alignment);3551 const new_offset = self.findFreeSpace(needed_size, alignment);
34933552
3494 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{3553 log.debug("moving '{s},{s}' from 0x{x} to 0x{x}", .{
3495 sect.segName(),3554 sect.segName(),
3496 sect.sectName(),3555 sect.sectName(),
3556 sect.offset,
3497 new_offset,3557 new_offset,
3498 new_offset + existing_size,
3499 });3558 });
35003559
3501 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);3560 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
...@@ -3557,6 +3616,22 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void...@@ -3557,6 +3616,22 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
3557 sect.size = needed_size;3616 sect.size = needed_size;
3558}3617}
35593618
3619pub fn markDirty(self: *MachO, sect_index: u8) void {
3620 if (self.getZigObject()) |zo| {
3621 if (self.debug_info_sect_index.? == sect_index) {
3622 zo.debug_info_header_dirty = true;
3623 } else if (self.debug_line_sect_index.? == sect_index) {
3624 zo.debug_line_header_dirty = true;
3625 } else if (self.debug_abbrev_sect_index.? == sect_index) {
3626 zo.debug_abbrev_dirty = true;
3627 } else if (self.debug_str_sect_index.? == sect_index) {
3628 zo.debug_strtab_dirty = true;
3629 } else if (self.debug_aranges_sect_index.? == sect_index) {
3630 zo.debug_aranges_dirty = true;
3631 }
3632 }
3633}
3634
3560pub fn getTarget(self: MachO) std.Target {3635pub fn getTarget(self: MachO) std.Target {
3561 return self.base.comp.root_mod.resolved_target.result;3636 return self.base.comp.root_mod.resolved_target.result;
3562}3637}
...@@ -3632,6 +3707,21 @@ pub fn isZigSection(self: MachO, sect_id: u8) bool {...@@ -3632,6 +3707,21 @@ pub fn isZigSection(self: MachO, sect_id: u8) bool {
3632 return false;3707 return false;
3633}3708}
36343709
3710pub fn isDebugSection(self: MachO, sect_id: u8) bool {
3711 inline for (&[_]?u8{
3712 self.debug_info_sect_index,
3713 self.debug_abbrev_sect_index,
3714 self.debug_str_sect_index,
3715 self.debug_aranges_sect_index,
3716 self.debug_line_sect_index,
3717 }) |maybe_index| {
3718 if (maybe_index) |index| {
3719 if (index == sect_id) return true;
3720 }
3721 }
3722 return false;
3723}
3724
3635pub fn addSegment(self: *MachO, name: []const u8, opts: struct {3725pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
3636 vmaddr: u64 = 0,3726 vmaddr: u64 = 0,
3637 vmsize: u64 = 0,3727 vmsize: u64 = 0,
src/link/MachO/DebugSymbols.zig+35-112
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1allocator: Allocator,1allocator: Allocator,
2dwarf: Dwarf,
3file: fs.File,2file: fs.File,
43
5symtab_cmd: macho.symtab_command = .{},4symtab_cmd: macho.symtab_command = .{},
...@@ -17,12 +16,6 @@ debug_str_section_index: ?u8 = null,...@@ -17,12 +16,6 @@ debug_str_section_index: ?u8 = null,
17debug_aranges_section_index: ?u8 = null,16debug_aranges_section_index: ?u8 = null,
18debug_line_section_index: ?u8 = null,17debug_line_section_index: ?u8 = null,
1918
20debug_string_table_dirty: bool = false,
21debug_abbrev_section_dirty: bool = false,
22debug_aranges_section_dirty: bool = false,
23debug_info_header_dirty: bool = false,
24debug_line_header_dirty: bool = false,
25
26relocs: std.ArrayListUnmanaged(Reloc) = .{},19relocs: std.ArrayListUnmanaged(Reloc) = .{},
2720
28/// Output synthetic sections21/// Output synthetic sections
...@@ -44,7 +37,7 @@ pub const Reloc = struct {...@@ -44,7 +37,7 @@ pub const Reloc = struct {
44pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {37pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
45 try self.strtab.append(self.allocator, 0);38 try self.strtab.append(self.allocator, 0);
4639
47 if (self.dwarf_segment_cmd_index == null) {40 {
48 self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));41 self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
4942
50 const page_size = macho_file.getPageSize();43 const page_size = macho_file.getPageSize();
...@@ -63,46 +56,19 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -63,46 +56,19 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void {
63 });56 });
64 }57 }
6558
66 if (self.debug_str_section_index == null) {59 self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0);
67 assert(self.dwarf.strtab.buffer.items.len == 0);60 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
68 try self.dwarf.strtab.buffer.append(self.allocator, 0);61 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
69 self.debug_str_section_index = try self.allocateSection(62 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
70 "__debug_str",63 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
71 @as(u32, @intCast(self.dwarf.strtab.buffer.items.len)),64
72 0,65 self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
73 );66 try self.segments.append(self.allocator, .{
74 self.debug_string_table_dirty = true;67 .segname = makeStaticString("__LINKEDIT"),
75 }68 .maxprot = macho.PROT.READ,
7669 .initprot = macho.PROT.READ,
77 if (self.debug_info_section_index == null) {70 .cmdsize = @sizeOf(macho.segment_command_64),
78 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);71 });
79 self.debug_info_header_dirty = true;
80 }
81
82 if (self.debug_abbrev_section_index == null) {
83 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
84 self.debug_abbrev_section_dirty = true;
85 }
86
87 if (self.debug_aranges_section_index == null) {
88 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
89 self.debug_aranges_section_dirty = true;
90 }
91
92 if (self.debug_line_section_index == null) {
93 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
94 self.debug_line_header_dirty = true;
95 }
96
97 if (self.linkedit_segment_cmd_index == null) {
98 self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
99 try self.segments.append(self.allocator, .{
100 .segname = makeStaticString("__LINKEDIT"),
101 .maxprot = macho.PROT.READ,
102 .initprot = macho.PROT.READ,
103 .cmdsize = @sizeOf(macho.segment_command_64),
104 });
105 }
106}72}
10773
108fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {74fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {
...@@ -133,7 +99,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -133,7 +99,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
133 return index;99 return index;
134}100}
135101
136pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requires_file_copy: bool) !void {102pub fn growSection(
103 self: *DebugSymbols,
104 sect_index: u8,
105 needed_size: u32,
106 requires_file_copy: bool,
107 macho_file: *MachO,
108) !void {
137 const sect = self.getSectionPtr(sect_index);109 const sect = self.getSectionPtr(sect_index);
138110
139 if (needed_size > self.allocatedSize(sect.offset)) {111 if (needed_size > self.allocatedSize(sect.offset)) {
...@@ -162,20 +134,22 @@ pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requir...@@ -162,20 +134,22 @@ pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requir
162 }134 }
163135
164 sect.size = needed_size;136 sect.size = needed_size;
165 self.markDirty(sect_index);137 self.markDirty(sect_index, macho_file);
166}138}
167139
168pub fn markDirty(self: *DebugSymbols, sect_index: u8) void {140pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void {
169 if (self.debug_info_section_index.? == sect_index) {141 if (macho_file.getZigObject()) |zo| {
170 self.debug_info_header_dirty = true;142 if (self.debug_info_section_index.? == sect_index) {
171 } else if (self.debug_line_section_index.? == sect_index) {143 zo.debug_info_header_dirty = true;
172 self.debug_line_header_dirty = true;144 } else if (self.debug_line_section_index.? == sect_index) {
173 } else if (self.debug_abbrev_section_index.? == sect_index) {145 zo.debug_line_header_dirty = true;
174 self.debug_abbrev_section_dirty = true;146 } else if (self.debug_abbrev_section_index.? == sect_index) {
175 } else if (self.debug_str_section_index.? == sect_index) {147 zo.debug_abbrev_dirty = true;
176 self.debug_string_table_dirty = true;148 } else if (self.debug_str_section_index.? == sect_index) {
177 } else if (self.debug_aranges_section_index.? == sect_index) {149 zo.debug_strtab_dirty = true;
178 self.debug_aranges_section_dirty = true;150 } else if (self.debug_aranges_section_index.? == sect_index) {
151 zo.debug_aranges_dirty = true;
152 }
179 }153 }
180}154}
181155
...@@ -201,13 +175,6 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64...@@ -201,13 +175,6 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64
201}175}
202176
203pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {177pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
204 const comp = macho_file.base.comp;
205 // TODO This linker code currently assumes there is only 1 compilation unit
206 // and it corresponds to the Zig source code.
207 const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
208
209 try self.dwarf.flushModule(zcu);
210
211 for (self.relocs.items) |*reloc| {178 for (self.relocs.items) |*reloc| {
212 const sym = macho_file.getSymbol(reloc.target);179 const sym = macho_file.getSymbol(reloc.target);
213 const sym_name = sym.getName(macho_file);180 const sym_name = sym.getName(macho_file);
...@@ -226,54 +193,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -226,54 +193,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
226 try self.file.pwriteAll(mem.asBytes(&addr), file_offset);193 try self.file.pwriteAll(mem.asBytes(&addr), file_offset);
227 }194 }
228195
229 if (self.debug_abbrev_section_dirty) {
230 try self.dwarf.writeDbgAbbrev();
231 self.debug_abbrev_section_dirty = false;
232 }
233
234 if (self.debug_info_header_dirty) {
235 // Currently only one compilation unit is supported, so the address range is simply
236 // identical to the main program header virtual address and memory size.
237 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
238 const low_pc = text_section.addr;
239 const high_pc = text_section.addr + text_section.size;
240 try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc);
241 self.debug_info_header_dirty = false;
242 }
243
244 if (self.debug_aranges_section_dirty) {
245 // Currently only one compilation unit is supported, so the address range is simply
246 // identical to the main program header virtual address and memory size.
247 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
248 try self.dwarf.writeDbgAranges(text_section.addr, text_section.size);
249 self.debug_aranges_section_dirty = false;
250 }
251
252 if (self.debug_line_header_dirty) {
253 try self.dwarf.writeDbgLineHeader();
254 self.debug_line_header_dirty = false;
255 }
256
257 {
258 const sect_index = self.debug_str_section_index.?;
259 if (self.debug_string_table_dirty or self.dwarf.strtab.buffer.items.len != self.getSection(sect_index).size) {
260 const needed_size = @as(u32, @intCast(self.dwarf.strtab.buffer.items.len));
261 try self.growSection(sect_index, needed_size, false);
262 try self.file.pwriteAll(self.dwarf.strtab.buffer.items, self.getSection(sect_index).offset);
263 self.debug_string_table_dirty = false;
264 }
265 }
266
267 self.finalizeDwarfSegment(macho_file);196 self.finalizeDwarfSegment(macho_file);
268 try self.writeLinkeditSegmentData(macho_file);197 try self.writeLinkeditSegmentData(macho_file);
269198
270 // Write load commands199 // Write load commands
271 const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file);200 const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file);
272 try self.writeHeader(macho_file, ncmds, sizeofcmds);201 try self.writeHeader(macho_file, ncmds, sizeofcmds);
273
274 assert(!self.debug_abbrev_section_dirty);
275 assert(!self.debug_aranges_section_dirty);
276 assert(!self.debug_string_table_dirty);
277}202}
278203
279pub fn deinit(self: *DebugSymbols) void {204pub fn deinit(self: *DebugSymbols) void {
...@@ -281,7 +206,6 @@ pub fn deinit(self: *DebugSymbols) void {...@@ -281,7 +206,6 @@ pub fn deinit(self: *DebugSymbols) void {
281 self.file.close();206 self.file.close();
282 self.segments.deinit(gpa);207 self.segments.deinit(gpa);
283 self.sections.deinit(gpa);208 self.sections.deinit(gpa);
284 self.dwarf.deinit();
285 self.relocs.deinit(gpa);209 self.relocs.deinit(gpa);
286 self.symtab.deinit(gpa);210 self.symtab.deinit(gpa);
287 self.strtab.deinit(gpa);211 self.strtab.deinit(gpa);
...@@ -534,7 +458,6 @@ const padToIdeal = MachO.padToIdeal;...@@ -534,7 +458,6 @@ const padToIdeal = MachO.padToIdeal;
534const trace = @import("../../tracy.zig").trace;458const trace = @import("../../tracy.zig").trace;
535459
536const Allocator = mem.Allocator;460const Allocator = mem.Allocator;
537const Dwarf = @import("../Dwarf.zig");
538const MachO = @import("../MachO.zig");461const MachO = @import("../MachO.zig");
539const StringTable = @import("../StringTable.zig");462const StringTable = @import("../StringTable.zig");
540const Type = @import("../../type.zig").Type;463const Type = @import("../../type.zig").Type;
src/link/MachO/ZigObject.zig+93-13
...@@ -46,16 +46,38 @@ tlv_initializers: TlvInitializerTable = .{},...@@ -46,16 +46,38 @@ tlv_initializers: TlvInitializerTable = .{},
46/// A table of relocations.46/// A table of relocations.
47relocs: RelocationTable = .{},47relocs: RelocationTable = .{},
4848
49dwarf: ?Dwarf = null,
50
49dynamic_relocs: MachO.DynamicRelocs = .{},51dynamic_relocs: MachO.DynamicRelocs = .{},
50output_symtab_ctx: MachO.SymtabCtx = .{},52output_symtab_ctx: MachO.SymtabCtx = .{},
51output_ar_state: Archive.ArState = .{},53output_ar_state: Archive.ArState = .{},
5254
55debug_strtab_dirty: bool = false,
56debug_abbrev_dirty: bool = false,
57debug_aranges_dirty: bool = false,
58debug_info_header_dirty: bool = false,
59debug_line_header_dirty: bool = false,
60
53pub fn init(self: *ZigObject, macho_file: *MachO) !void {61pub fn init(self: *ZigObject, macho_file: *MachO) !void {
54 const comp = macho_file.base.comp;62 const comp = macho_file.base.comp;
55 const gpa = comp.gpa;63 const gpa = comp.gpa;
5664
57 try self.atoms.append(gpa, 0); // null input section65 try self.atoms.append(gpa, 0); // null input section
58 try self.strtab.buffer.append(gpa, 0);66 try self.strtab.buffer.append(gpa, 0);
67
68 switch (comp.config.debug_format) {
69 .strip => {},
70 .dwarf => |v| {
71 assert(v == .@"32");
72 self.dwarf = Dwarf.init(&macho_file.base, .dwarf32);
73 self.debug_strtab_dirty = true;
74 self.debug_abbrev_dirty = true;
75 self.debug_aranges_dirty = true;
76 self.debug_info_header_dirty = true;
77 self.debug_line_header_dirty = true;
78 },
79 .code_view => unreachable,
80 }
59}81}
6082
61pub fn deinit(self: *ZigObject, allocator: Allocator) void {83pub fn deinit(self: *ZigObject, allocator: Allocator) void {
...@@ -101,6 +123,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -101,6 +123,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
101 tlv_init.deinit(allocator);123 tlv_init.deinit(allocator);
102 }124 }
103 self.tlv_initializers.deinit(allocator);125 self.tlv_initializers.deinit(allocator);
126
127 if (self.dwarf) |*dw| {
128 dw.deinit();
129 }
104}130}
105131
106fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {132fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {
...@@ -407,6 +433,66 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO) !void {...@@ -407,6 +433,66 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO) !void {
407 if (metadata.text_state != .unused) metadata.text_state = .flushed;433 if (metadata.text_state != .unused) metadata.text_state = .flushed;
408 if (metadata.const_state != .unused) metadata.const_state = .flushed;434 if (metadata.const_state != .unused) metadata.const_state = .flushed;
409 }435 }
436
437 if (self.dwarf) |*dw| {
438 const zcu = macho_file.base.comp.module.?;
439 try dw.flushModule(zcu);
440
441 if (self.debug_abbrev_dirty) {
442 try dw.writeDbgAbbrev();
443 self.debug_abbrev_dirty = false;
444 }
445
446 if (self.debug_info_header_dirty) {
447 // Currently only one compilation unit is supported, so the address range is simply
448 // identical to the main program header virtual address and memory size.
449 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
450 const low_pc = text_section.addr;
451 const high_pc = text_section.addr + text_section.size;
452 try dw.writeDbgInfoHeader(zcu, low_pc, high_pc);
453 self.debug_info_header_dirty = false;
454 }
455
456 if (self.debug_aranges_dirty) {
457 // Currently only one compilation unit is supported, so the address range is simply
458 // identical to the main program header virtual address and memory size.
459 const text_section = macho_file.sections.items(.header)[macho_file.zig_text_sect_index.?];
460 try dw.writeDbgAranges(text_section.addr, text_section.size);
461 self.debug_aranges_dirty = false;
462 }
463
464 if (self.debug_line_header_dirty) {
465 try dw.writeDbgLineHeader();
466 self.debug_line_header_dirty = false;
467 }
468
469 if (!macho_file.base.isRelocatable()) {
470 const d_sym = macho_file.getDebugSymbols().?;
471 const sect_index = d_sym.debug_str_section_index.?;
472 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != d_sym.getSection(sect_index).size) {
473 const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
474 try d_sym.growSection(sect_index, needed_size, false, macho_file);
475 try d_sym.file.pwriteAll(dw.strtab.buffer.items, d_sym.getSection(sect_index).offset);
476 self.debug_strtab_dirty = false;
477 }
478 } else {
479 const sect_index = macho_file.debug_str_sect_index.?;
480 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != macho_file.sections.items(.header)[sect_index].size) {
481 const needed_size = @as(u32, @intCast(dw.strtab.buffer.items.len));
482 try macho_file.growSection(sect_index, needed_size);
483 try macho_file.base.file.?.pwriteAll(dw.strtab.buffer.items, macho_file.sections.items(.header)[sect_index].offset);
484 self.debug_strtab_dirty = false;
485 }
486 }
487 }
488
489 // The point of flushModule() is to commit changes, so in theory, nothing should
490 // be dirty after this. However, it is possible for some things to remain
491 // dirty because they fail to be written in the event of compile errors,
492 // such as debug_line_header_dirty and debug_info_header_dirty.
493 assert(!self.debug_abbrev_dirty);
494 assert(!self.debug_aranges_dirty);
495 assert(!self.debug_strtab_dirty);
410}496}
411497
412pub fn getDeclVAddr(498pub fn getDeclVAddr(
...@@ -572,7 +658,7 @@ pub fn updateFunc(...@@ -572,7 +658,7 @@ pub fn updateFunc(
572 var code_buffer = std.ArrayList(u8).init(gpa);658 var code_buffer = std.ArrayList(u8).init(gpa);
573 defer code_buffer.deinit();659 defer code_buffer.deinit();
574660
575 var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;661 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
576 defer if (decl_state) |*ds| ds.deinit();662 defer if (decl_state) |*ds| ds.deinit();
577663
578 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;664 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
...@@ -600,7 +686,7 @@ pub fn updateFunc(...@@ -600,7 +686,7 @@ pub fn updateFunc(
600686
601 if (decl_state) |*ds| {687 if (decl_state) |*ds| {
602 const sym = macho_file.getSymbol(sym_index);688 const sym = macho_file.getSymbol(sym_index);
603 try macho_file.getDebugSymbols().?.dwarf.commitDeclState(689 try self.dwarf.?.commitDeclState(
604 mod,690 mod,
605 decl_index,691 decl_index,
606 sym.getAddress(.{}, macho_file),692 sym.getAddress(.{}, macho_file),
...@@ -647,7 +733,7 @@ pub fn updateDecl(...@@ -647,7 +733,7 @@ pub fn updateDecl(
647 var code_buffer = std.ArrayList(u8).init(gpa);733 var code_buffer = std.ArrayList(u8).init(gpa);
648 defer code_buffer.deinit();734 defer code_buffer.deinit();
649735
650 var decl_state: ?Dwarf.DeclState = if (macho_file.getDebugSymbols()) |d_sym| try d_sym.dwarf.initDeclState(mod, decl_index) else null;736 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
651 defer if (decl_state) |*ds| ds.deinit();737 defer if (decl_state) |*ds| ds.deinit();
652738
653 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;739 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
...@@ -681,7 +767,7 @@ pub fn updateDecl(...@@ -681,7 +767,7 @@ pub fn updateDecl(
681767
682 if (decl_state) |*ds| {768 if (decl_state) |*ds| {
683 const sym = macho_file.getSymbol(sym_index);769 const sym = macho_file.getSymbol(sym_index);
684 try macho_file.getDebugSymbols().?.dwarf.commitDeclState(770 try self.dwarf.?.commitDeclState(
685 mod,771 mod,
686 decl_index,772 decl_index,
687 sym.getAddress(.{}, macho_file),773 sym.getAddress(.{}, macho_file),
...@@ -1257,15 +1343,9 @@ fn updateLazySymbol(...@@ -1257,15 +1343,9 @@ fn updateLazySymbol(
1257}1343}
12581344
1259/// Must be called only after a successful call to `updateDecl`.1345/// Must be called only after a successful call to `updateDecl`.
1260pub fn updateDeclLineNumber(1346pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void {
1261 self: *ZigObject,1347 if (self.dwarf) |*dw| {
1262 macho_file: *MachO,1348 try dw.updateDeclLineNumber(mod, decl_index);
1263 mod: *Module,
1264 decl_index: InternPool.DeclIndex,
1265) !void {
1266 _ = self;
1267 if (macho_file.getDebugSymbols()) |d_sym| {
1268 try d_sym.dwarf.updateDeclLineNumber(mod, decl_index);
1269 }1349 }
1270}1350}
12711351
src/link/MachO/relocatable.zig+21-19
...@@ -193,8 +193,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -193,8 +193,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
193 // Update file offsets of contributing objects193 // Update file offsets of contributing objects
194 const total_size: usize = blk: {194 const total_size: usize = blk: {
195 var pos: usize = Archive.SARMAG;195 var pos: usize = Archive.SARMAG;
196 pos += @sizeOf(Archive.ar_hdr) + Archive.SYMDEF.len + 1;196 pos += @sizeOf(Archive.ar_hdr);
197 pos = mem.alignForward(usize, pos, ptr_width);197 pos += mem.alignForward(usize, Archive.SYMDEF.len + 1, ptr_width);
198 pos += ar_symtab.size(format);198 pos += ar_symtab.size(format);
199199
200 for (files.items) |index| {200 for (files.items) |index| {
...@@ -209,10 +209,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -209,10 +209,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
209 .object => |x| x.path,209 .object => |x| x.path,
210 else => unreachable,210 else => unreachable,
211 };211 };
212 pos = mem.alignForward(usize, pos, ptr_width);212 pos = mem.alignForward(usize, pos, 2);
213 state.file_off = pos;213 state.file_off = pos;
214 pos += @sizeOf(Archive.ar_hdr) + path.len + 1;214 pos += @sizeOf(Archive.ar_hdr);
215 pos = mem.alignForward(usize, pos, ptr_width);215 pos += mem.alignForward(usize, path.len + 1, ptr_width);
216 pos += math.cast(usize, state.size) orelse return error.Overflow;216 pos += math.cast(usize, state.size) orelse return error.Overflow;
217 }217 }
218218
...@@ -236,7 +236,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -236,7 +236,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
236236
237 // Write object files237 // Write object files
238 for (files.items) |index| {238 for (files.items) |index| {
239 const aligned = mem.alignForward(usize, buffer.items.len, ptr_width);239 const aligned = mem.alignForward(usize, buffer.items.len, 2);
240 const padding = aligned - buffer.items.len;240 const padding = aligned - buffer.items.len;
241 if (padding > 0) {241 if (padding > 0) {
242 try writer.writeByteNTimes(0, padding);242 try writer.writeByteNTimes(0, padding);
...@@ -402,7 +402,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -402,7 +402,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
402 const atom = macho_file.getAtom(atom_index) orelse continue;402 const atom = macho_file.getAtom(atom_index) orelse continue;
403 if (!atom.flags.alive) continue;403 if (!atom.flags.alive) continue;
404 const header = &macho_file.sections.items(.header)[atom.out_n_sect];404 const header = &macho_file.sections.items(.header)[atom.out_n_sect];
405 if (!macho_file.isZigSection(atom.out_n_sect)) continue;405 if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
406 header.nreloc += atom.calcNumRelocs(macho_file);406 header.nreloc += atom.calcNumRelocs(macho_file);
407 }407 }
408 }408 }
...@@ -436,18 +436,20 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {...@@ -436,18 +436,20 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
436436
437fn allocateSections(macho_file: *MachO) !void {437fn allocateSections(macho_file: *MachO) !void {
438 const slice = macho_file.sections.slice();438 const slice = macho_file.sections.slice();
439439 for (slice.items(.header)) |*header| {
440 const last_index = for (0..slice.items(.header).len) |i| {440 const needed_size = header.size;
441 if (macho_file.isZigSection(@intCast(i))) break i;441 header.size = 0;
442 } else slice.items(.header).len;
443
444 for (slice.items(.header)[0..last_index]) |*header| {
445 const alignment = try math.powi(u32, 2, header.@"align");442 const alignment = try math.powi(u32, 2, header.@"align");
446 if (!header.isZerofill()) {443 if (!header.isZerofill()) {
447 header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse444 if (needed_size > macho_file.allocatedSize(header.offset)) {
448 return error.Overflow;445 header.offset = math.cast(u32, macho_file.findFreeSpace(needed_size, alignment)) orelse
446 return error.Overflow;
447 }
448 }
449 if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {
450 header.addr = macho_file.findFreeSpaceVirtual(needed_size, alignment);
449 }451 }
450 header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment);452 header.size = needed_size;
451 }453 }
452}454}
453455
...@@ -539,7 +541,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -539,7 +541,7 @@ fn writeAtoms(macho_file: *MachO) !void {
539 for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {541 for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
540 if (atoms.items.len == 0) continue;542 if (atoms.items.len == 0) continue;
541 if (header.isZerofill()) continue;543 if (header.isZerofill()) continue;
542 if (macho_file.isZigSection(@intCast(i))) continue;544 if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue;
543545
544 const size = math.cast(usize, header.size) orelse return error.Overflow;546 const size = math.cast(usize, header.size) orelse return error.Overflow;
545 const code = try gpa.alloc(u8, size);547 const code = try gpa.alloc(u8, size);
...@@ -580,7 +582,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -580,7 +582,7 @@ fn writeAtoms(macho_file: *MachO) !void {
580582
581 for (macho_file.sections.items(.header), 0..) |header, n_sect| {583 for (macho_file.sections.items(.header), 0..) |header, n_sect| {
582 if (header.isZerofill()) continue;584 if (header.isZerofill()) continue;
583 if (!macho_file.isZigSection(@intCast(n_sect))) continue;585 if (!macho_file.isZigSection(@intCast(n_sect)) and !macho_file.isDebugSection(@intCast(n_sect))) continue;
584 const gop = try relocs.getOrPut(@intCast(n_sect));586 const gop = try relocs.getOrPut(@intCast(n_sect));
585 if (gop.found_existing) continue;587 if (gop.found_existing) continue;
586 gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);588 gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
...@@ -591,7 +593,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -591,7 +593,7 @@ fn writeAtoms(macho_file: *MachO) !void {
591 if (!atom.flags.alive) continue;593 if (!atom.flags.alive) continue;
592 const header = macho_file.sections.items(.header)[atom.out_n_sect];594 const header = macho_file.sections.items(.header)[atom.out_n_sect];
593 if (header.isZerofill()) continue;595 if (header.isZerofill()) continue;
594 if (!macho_file.isZigSection(atom.out_n_sect)) continue;596 if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
595 if (atom.getRelocs(macho_file).len == 0) continue;597 if (atom.getRelocs(macho_file).len == 0) continue;
596 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;598 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
597 const code = try gpa.alloc(u8, atom_size);599 const code = try gpa.alloc(u8, atom_size);
test/link/macho.zig+45-9
...@@ -20,8 +20,11 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -20,8 +20,11 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
20 };20 };
2121
22 // Exercise linker with self-hosted backend (no LLVM)22 // Exercise linker with self-hosted backend (no LLVM)
23 macho_step.dependOn(testEmptyZig(b, .{ .use_llvm = false, .target = x86_64_target }));
23 macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target }));24 macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target }));
24 macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .strip = true, .target = x86_64_target }));25 macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target }));
26 macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target }));
27 macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target }));
2528
26 // Exercise linker with LLVM backend29 // Exercise linker with LLVM backend
27 macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));30 macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
...@@ -33,6 +36,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -33,6 +36,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
33 macho_step.dependOn(testHelloZig(b, .{ .target = default_target }));36 macho_step.dependOn(testHelloZig(b, .{ .target = default_target }));
34 macho_step.dependOn(testLargeBss(b, .{ .target = default_target }));37 macho_step.dependOn(testLargeBss(b, .{ .target = default_target }));
35 macho_step.dependOn(testLayout(b, .{ .target = default_target }));38 macho_step.dependOn(testLayout(b, .{ .target = default_target }));
39 macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target }));
36 macho_step.dependOn(testLinksection(b, .{ .target = default_target }));40 macho_step.dependOn(testLinksection(b, .{ .target = default_target }));
37 macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target }));41 macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target }));
38 macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target }));42 macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target }));
...@@ -843,6 +847,45 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {...@@ -843,6 +847,45 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
843 return test_step;847 return test_step;
844}848}
845849
850fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
851 const test_step = addTestStep(b, "linking-static-lib", opts);
852
853 const obj = addObject(b, opts, .{
854 .name = "bobj",
855 .zig_source_bytes = "export var bar: i32 = -42;",
856 .strip = true, // TODO for self-hosted, we don't really emit any valid DWARF yet since we only export a global
857 });
858
859 const lib = addStaticLibrary(b, opts, .{
860 .name = "alib",
861 .zig_source_bytes =
862 \\export fn foo() i32 {
863 \\ return 42;
864 \\}
865 ,
866 });
867 lib.addObject(obj);
868
869 const exe = addExecutable(b, opts, .{
870 .name = "testlib",
871 .zig_source_bytes =
872 \\const std = @import("std");
873 \\extern fn foo() i32;
874 \\extern var bar: i32;
875 \\pub fn main() void {
876 \\ std.debug.print("{d}\n", .{foo() + bar});
877 \\}
878 ,
879 });
880 exe.linkLibrary(lib);
881
882 const run = addRunArtifact(exe);
883 run.expectStdErrEqual("0\n");
884 test_step.dependOn(&run.step);
885
886 return test_step;
887}
888
846fn testLinksection(b: *Build, opts: Options) *Step {889fn testLinksection(b: *Build, opts: Options) *Step {
847 const test_step = addTestStep(b, "macho-linksection", opts);890 const test_step = addTestStep(b, "macho-linksection", opts);
848891
...@@ -1243,14 +1286,7 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {...@@ -1243,14 +1286,7 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
1243 const run = addRunArtifact(exe);1286 const run = addRunArtifact(exe);
1244 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });1287 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
1245 run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") });1288 run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") });
1246 if (opts.use_llvm) {1289 run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") });
1247 // TODO: enable this once self-hosted can print panics and stack traces
1248 run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") });
1249 }
1250 if (builtin.os.tag == .macos) {
1251 const signal: u32 = if (opts.use_llvm) std.os.darwin.SIG.ABRT else std.os.darwin.SIG.TRAP;
1252 run.addCheck(.{ .expect_term = .{ .Signal = signal } });
1253 }
1254 test_step.dependOn(&run.step);1290 test_step.dependOn(&run.step);
12551291
1256 return test_step;1292 return test_step;