| author | |
| committer | |
| log | d12c8db6421f28ca59c03b619c70126c6694b0d4 |
| tree | 803f5500302741169e17e9e5a72a90f28fdb403a |
| parent | 6fb23542fe8503ba5c97bde950b1ebbe8f07f951 |
| parent | 83bbc39c1582077cb5385536a04b7bf8bbffbf26 |
| signature |
macho: emit DWARF for ZigObject relocatable9 files changed, 541 insertions(+), 283 deletions(-)
ci/x86_64-macos-release.sh+9| ... | ... | @@ -25,6 +25,15 @@ cd $ZIGDIR |
| 25 | 25 | git fetch --unshallow || true |
| 26 | 26 | git fetch --tags |
| 27 | 27 | |
| 28 | # Test building from source without LLVM. | |
| 29 | git clean -fd | |
| 30 | rm -rf zig-out | |
| 31 | cc -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 | ||
| 28 | 37 | rm -rf build |
| 29 | 38 | mkdir build |
| 30 | 39 | cd 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 | 764 | builtin.zig_backend == .stage2_arm or |
| 765 | 765 | builtin.zig_backend == .stage2_aarch64 or |
| 766 | 766 | builtin.zig_backend == .stage2_x86 or |
| 767 | (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) or | |
| 767 | (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or | |
| 768 | 768 | builtin.zig_backend == .stage2_riscv64 or |
| 769 | 769 | builtin.zig_backend == .stage2_sparc64 or |
| 770 | 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 | 6278 | } |
| 6279 | 6279 | return switch (target_util.zigBackend(target, use_llvm)) { |
| 6280 | 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 | 6282 | else => build_options.have_llvm, |
| 6283 | 6283 | }; |
| 6284 | 6284 | } |
| ... | ... | @@ -6296,7 +6296,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool { |
| 6296 | 6296 | } |
| 6297 | 6297 | return switch (target_util.zigBackend(target, use_llvm)) { |
| 6298 | 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 | 6300 | else => build_options.have_llvm, |
| 6301 | 6301 | }; |
| 6302 | 6302 | } |
src/link/Dwarf.zig+200-82| ... | ... | @@ -1282,10 +1282,17 @@ pub fn commitDeclState( |
| 1282 | 1282 | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); |
| 1283 | 1283 | }, |
| 1284 | 1284 | .macho => { |
| 1285 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1286 | const debug_line_sect = d_sym.getSectionPtr(d_sym.debug_line_section_index.?); | |
| 1287 | const file_pos = debug_line_sect.offset + src_fn.off; | |
| 1288 | try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len); | |
| 1285 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1286 | if (macho_file.base.isRelocatable()) { | |
| 1287 | const debug_line_sect = &macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; | |
| 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 | 1297 | .wasm => { |
| 1291 | 1298 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| ... | ... | @@ -1351,18 +1358,33 @@ pub fn commitDeclState( |
| 1351 | 1358 | }, |
| 1352 | 1359 | |
| 1353 | 1360 | .macho => { |
| 1354 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1355 | const sect_index = d_sym.debug_line_section_index.?; | |
| 1356 | try d_sym.growSection(sect_index, needed_size, true); | |
| 1357 | const sect = d_sym.getSection(sect_index); | |
| 1358 | const file_pos = sect.offset + src_fn.off; | |
| 1359 | try pwriteDbgLineNops( | |
| 1360 | d_sym.file, | |
| 1361 | file_pos, | |
| 1362 | prev_padding_size, | |
| 1363 | dbg_line_buffer.items, | |
| 1364 | next_padding_size, | |
| 1365 | ); | |
| 1361 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1362 | if (macho_file.base.isRelocatable()) { | |
| 1363 | const sect_index = macho_file.debug_line_sect_index.?; | |
| 1364 | try macho_file.growSection(sect_index, needed_size); | |
| 1365 | const sect = macho_file.sections.items(.header)[sect_index]; | |
| 1366 | const file_pos = sect.offset + src_fn.off; | |
| 1367 | try pwriteDbgLineNops( | |
| 1368 | macho_file.base.file.?, | |
| 1369 | file_pos, | |
| 1370 | prev_padding_size, | |
| 1371 | dbg_line_buffer.items, | |
| 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 | }, |
| 1367 | 1389 | |
| 1368 | 1390 | .wasm => { |
| ... | ... | @@ -1459,16 +1481,21 @@ pub fn commitDeclState( |
| 1459 | 1481 | while (decl_state.exprloc_relocs.popOrNull()) |reloc| { |
| 1460 | 1482 | switch (self.bin_file.tag) { |
| 1461 | 1483 | .macho => { |
| 1462 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1463 | try d_sym.relocs.append(d_sym.allocator, .{ | |
| 1464 | .type = switch (reloc.type) { | |
| 1465 | .direct_load => .direct_load, | |
| 1466 | .got_load => .got_load, | |
| 1467 | }, | |
| 1468 | .target = reloc.target, | |
| 1469 | .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off, | |
| 1470 | .addend = 0, | |
| 1471 | }); | |
| 1484 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1485 | if (macho_file.base.isRelocatable()) { | |
| 1486 | // TODO | |
| 1487 | } else { | |
| 1488 | const d_sym = macho_file.getDebugSymbols().?; | |
| 1489 | try d_sym.relocs.append(d_sym.allocator, .{ | |
| 1490 | .type = switch (reloc.type) { | |
| 1491 | .direct_load => .direct_load, | |
| 1492 | .got_load => .got_load, | |
| 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 | 1500 | .elf => {}, // TODO |
| 1474 | 1501 | else => unreachable, |
| ... | ... | @@ -1511,10 +1538,17 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) |
| 1511 | 1538 | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); |
| 1512 | 1539 | }, |
| 1513 | 1540 | .macho => { |
| 1514 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1515 | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); | |
| 1516 | const file_pos = debug_info_sect.offset + atom.off; | |
| 1517 | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false); | |
| 1541 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1542 | if (macho_file.base.isRelocatable()) { | |
| 1543 | const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?]; | |
| 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 | 1553 | .wasm => { |
| 1520 | 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 | 1631 | }, |
| 1598 | 1632 | |
| 1599 | 1633 | .macho => { |
| 1600 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1601 | const sect_index = d_sym.debug_info_section_index.?; | |
| 1602 | try d_sym.growSection(sect_index, needed_size, true); | |
| 1603 | const sect = d_sym.getSection(sect_index); | |
| 1604 | const file_pos = sect.offset + atom.off; | |
| 1605 | try pwriteDbgInfoNops( | |
| 1606 | d_sym.file, | |
| 1607 | file_pos, | |
| 1608 | prev_padding_size, | |
| 1609 | dbg_info_buf, | |
| 1610 | next_padding_size, | |
| 1611 | trailing_zero, | |
| 1612 | ); | |
| 1634 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1635 | if (macho_file.base.isRelocatable()) { | |
| 1636 | const sect_index = macho_file.debug_info_sect_index.?; | |
| 1637 | try macho_file.growSection(sect_index, needed_size); | |
| 1638 | const sect = macho_file.sections.items(.header)[sect_index]; | |
| 1639 | const file_pos = sect.offset + atom.off; | |
| 1640 | try pwriteDbgInfoNops( | |
| 1641 | macho_file.base.file.?, | |
| 1642 | file_pos, | |
| 1643 | prev_padding_size, | |
| 1644 | dbg_info_buf, | |
| 1645 | next_padding_size, | |
| 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 | }, |
| 1614 | 1664 | |
| 1615 | 1665 | .wasm => { |
| ... | ... | @@ -1670,10 +1720,17 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D |
| 1670 | 1720 | try elf_file.base.file.?.pwriteAll(&data, file_pos); |
| 1671 | 1721 | }, |
| 1672 | 1722 | .macho => { |
| 1673 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1674 | const sect = d_sym.getSection(d_sym.debug_line_section_index.?); | |
| 1675 | const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff(); | |
| 1676 | try d_sym.file.pwriteAll(&data, file_pos); | |
| 1723 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1724 | if (macho_file.base.isRelocatable()) { | |
| 1725 | const sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; | |
| 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 | 1735 | .wasm => { |
| 1679 | 1736 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| ... | ... | @@ -1877,12 +1934,21 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { |
| 1877 | 1934 | try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); |
| 1878 | 1935 | }, |
| 1879 | 1936 | .macho => { |
| 1880 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1881 | const sect_index = d_sym.debug_abbrev_section_index.?; | |
| 1882 | try d_sym.growSection(sect_index, needed_size, false); | |
| 1883 | const sect = d_sym.getSection(sect_index); | |
| 1884 | const file_pos = sect.offset + abbrev_offset; | |
| 1885 | try d_sym.file.pwriteAll(&abbrev_buf, file_pos); | |
| 1937 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 1938 | if (macho_file.base.isRelocatable()) { | |
| 1939 | const sect_index = macho_file.debug_abbrev_sect_index.?; | |
| 1940 | try macho_file.growSection(sect_index, needed_size); | |
| 1941 | const sect = macho_file.sections.items(.header)[sect_index]; | |
| 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 | 1953 | .wasm => { |
| 1888 | 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 | 2033 | try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); |
| 1968 | 2034 | }, |
| 1969 | 2035 | .macho => { |
| 1970 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 1971 | const debug_info_sect = d_sym.getSection(d_sym.debug_info_section_index.?); | |
| 1972 | const file_pos = debug_info_sect.offset; | |
| 1973 | try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false); | |
| 2036 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 2037 | if (macho_file.base.isRelocatable()) { | |
| 2038 | const debug_info_sect = macho_file.sections.items(.header)[macho_file.debug_info_sect_index.?]; | |
| 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 | 2048 | .wasm => { |
| 1976 | 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 | 2365 | try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); |
| 2293 | 2366 | }, |
| 2294 | 2367 | .macho => { |
| 2295 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2296 | const sect_index = d_sym.debug_aranges_section_index.?; | |
| 2297 | try d_sym.growSection(sect_index, needed_size, false); | |
| 2298 | const sect = d_sym.getSection(sect_index); | |
| 2299 | const file_pos = sect.offset; | |
| 2300 | try d_sym.file.pwriteAll(di_buf.items, file_pos); | |
| 2368 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 2369 | if (macho_file.base.isRelocatable()) { | |
| 2370 | const sect_index = macho_file.debug_aranges_sect_index.?; | |
| 2371 | try macho_file.growSection(sect_index, needed_size); | |
| 2372 | const sect = macho_file.sections.items(.header)[sect_index]; | |
| 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 | 2384 | .wasm => { |
| 2303 | 2385 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| ... | ... | @@ -2432,16 +2514,29 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2432 | 2514 | try elf_file.base.file.?.pwriteAll(buffer, file_pos + delta); |
| 2433 | 2515 | }, |
| 2434 | 2516 | .macho => { |
| 2435 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2436 | const sect_index = d_sym.debug_line_section_index.?; | |
| 2437 | const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta); | |
| 2438 | try d_sym.growSection(sect_index, needed_size, true); | |
| 2439 | const file_pos = d_sym.getSection(sect_index).offset + first_fn.off; | |
| 2517 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 2518 | if (macho_file.base.isRelocatable()) { | |
| 2519 | const sect_index = macho_file.debug_line_sect_index.?; | |
| 2520 | const needed_size: u32 = @intCast(macho_file.sections.items(.header)[sect_index].size + delta); | |
| 2521 | try macho_file.growSection(sect_index, needed_size); | |
| 2522 | const file_pos = macho_file.sections.items(.header)[sect_index].offset + first_fn.off; | |
| 2440 | 2523 | |
| 2441 | const amt = try d_sym.file.preadAll(buffer, file_pos); | |
| 2442 | if (amt != buffer.len) return error.InputOutput; | |
| 2524 | const amt = try macho_file.base.file.?.preadAll(buffer, file_pos); | |
| 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; | |
| 2443 | 2537 | |
| 2444 | try d_sym.file.pwriteAll(buffer, file_pos + delta); | |
| 2538 | try d_sym.file.pwriteAll(buffer, file_pos + delta); | |
| 2539 | } | |
| 2445 | 2540 | }, |
| 2446 | 2541 | .wasm => { |
| 2447 | 2542 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| ... | ... | @@ -2487,10 +2582,17 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2487 | 2582 | try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); |
| 2488 | 2583 | }, |
| 2489 | 2584 | .macho => { |
| 2490 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2491 | const debug_line_sect = d_sym.getSection(d_sym.debug_line_section_index.?); | |
| 2492 | const file_pos = debug_line_sect.offset; | |
| 2493 | try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt); | |
| 2585 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 2586 | if (macho_file.base.isRelocatable()) { | |
| 2587 | const debug_line_sect = macho_file.sections.items(.header)[macho_file.debug_line_sect_index.?]; | |
| 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 | 2597 | .wasm => { |
| 2496 | 2598 | const wasm_file = self.bin_file.cast(File.Wasm).?; |
| ... | ... | @@ -2608,9 +2710,15 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2608 | 2710 | break :pos debug_info_sect.sh_offset; |
| 2609 | 2711 | }, |
| 2610 | 2712 | .macho => pos: { |
| 2611 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2612 | const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?); | |
| 2613 | break :pos debug_info_sect.offset; | |
| 2713 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 2714 | if (macho_file.base.isRelocatable()) { | |
| 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 | 2723 | // for wasm, the offset is always 0 as we write to memory first |
| 2616 | 2724 | .wasm => 0, |
| ... | ... | @@ -2628,8 +2736,13 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2628 | 2736 | try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset); |
| 2629 | 2737 | }, |
| 2630 | 2738 | .macho => { |
| 2631 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2632 | try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset); | |
| 2739 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 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 | 2747 | .wasm => { |
| 2635 | 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 | 2766 | elf_file.markDirty(elf_file.debug_line_section_index.?); |
| 2654 | 2767 | }, |
| 2655 | 2768 | .macho => { |
| 2656 | const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; | |
| 2657 | d_sym.markDirty(d_sym.debug_line_section_index.?); | |
| 2769 | const macho_file = self.bin_file.cast(File.MachO).?; | |
| 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 | 2777 | .wasm => {}, |
| 2660 | 2778 | else => unreachable, |
src/link/MachO.zig+135-45| ... | ... | @@ -103,6 +103,14 @@ zig_const_sect_index: ?u8 = null, |
| 103 | 103 | zig_data_sect_index: ?u8 = null, |
| 104 | 104 | zig_bss_sect_index: ?u8 = null, |
| 105 | 105 | |
| 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. | |
| 108 | debug_info_sect_index: ?u8 = null, | |
| 109 | debug_abbrev_sect_index: ?u8 = null, | |
| 110 | debug_str_sect_index: ?u8 = null, | |
| 111 | debug_aranges_sect_index: ?u8 = null, | |
| 112 | debug_line_sect_index: ?u8 = null, | |
| 113 | ||
| 106 | 114 | has_tlv: bool = false, |
| 107 | 115 | binds_to_weak: bool = false, |
| 108 | 116 | weak_defines: bool = false, |
| ... | ... | @@ -255,44 +263,15 @@ pub fn createEmpty( |
| 255 | 263 | )}), |
| 256 | 264 | } }); |
| 257 | 265 | self.zig_object = index; |
| 258 | try self.getZigObject().?.init(self); | |
| 266 | const zo = self.getZigObject().?; | |
| 267 | try zo.init(self); | |
| 268 | ||
| 259 | 269 | try self.initMetadata(.{ |
| 270 | .emit = emit, | |
| 271 | .zo = zo, | |
| 260 | 272 | .symbol_count_hint = options.symbol_count_hint, |
| 261 | 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 | } |
| 298 | 277 | |
| ... | ... | @@ -978,7 +957,6 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { |
| 978 | 957 | |
| 979 | 958 | const gpa = self.base.comp.gpa; |
| 980 | 959 | const file = try std.fs.cwd().openFile(path, .{}); |
| 981 | errdefer file.close(); | |
| 982 | 960 | const handle = try self.addFileHandle(file); |
| 983 | 961 | const mtime: u64 = mtime: { |
| 984 | 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 | 993 | const gpa = self.base.comp.gpa; |
| 1016 | 994 | |
| 1017 | 995 | const file = try std.fs.cwd().openFile(lib.path, .{}); |
| 1018 | errdefer file.close(); | |
| 1019 | 996 | const handle = try self.addFileHandle(file); |
| 1020 | 997 | |
| 1021 | 998 | var archive = Archive{}; |
| ... | ... | @@ -2015,6 +1992,11 @@ pub fn sortSections(self: *MachO) !void { |
| 2015 | 1992 | &self.eh_frame_sect_index, |
| 2016 | 1993 | &self.unwind_info_sect_index, |
| 2017 | 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 | 2000 | }) |maybe_index| { |
| 2019 | 2001 | if (maybe_index.*) |*index| { |
| 2020 | 2002 | index.* = backlinks[index.*]; |
| ... | ... | @@ -2314,11 +2296,11 @@ fn allocateSections(self: *MachO) !void { |
| 2314 | 2296 | // Must move the entire section. |
| 2315 | 2297 | const new_offset = self.findFreeSpace(existing_size, page_size); |
| 2316 | 2298 | |
| 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 | 2300 | header.segName(), |
| 2319 | 2301 | header.sectName(), |
| 2302 | header.offset, | |
| 2320 | 2303 | new_offset, |
| 2321 | new_offset + existing_size, | |
| 2322 | 2304 | }); |
| 2323 | 2305 | |
| 2324 | 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 | 3134 | |
| 3153 | 3135 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: InternPool.DeclIndex) !void { |
| 3154 | 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 | } |
| 3157 | 3139 | |
| 3158 | 3140 | pub fn updateExports( |
| ... | ... | @@ -3221,7 +3203,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 3221 | 3203 | for (self.sections.items(.header)) |header| { |
| 3222 | 3204 | if (header.isZerofill()) continue; |
| 3223 | 3205 | const increased_size = padToIdeal(header.size); |
| 3224 | const test_end = header.offset + increased_size; | |
| 3206 | const test_end = header.offset +| increased_size; | |
| 3225 | 3207 | if (end > header.offset and start < test_end) { |
| 3226 | 3208 | return test_end; |
| 3227 | 3209 | } |
| ... | ... | @@ -3249,7 +3231,7 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 { |
| 3249 | 3231 | |
| 3250 | 3232 | for (self.sections.items(.header)) |header| { |
| 3251 | 3233 | const increased_size = padToIdeal(header.size); |
| 3252 | const test_end = header.addr + increased_size; | |
| 3234 | const test_end = header.addr +| increased_size; | |
| 3253 | 3235 | if (end > header.addr and start < test_end) { |
| 3254 | 3236 | return test_end; |
| 3255 | 3237 | } |
| ... | ... | @@ -3266,27 +3248,39 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 { |
| 3266 | 3248 | return null; |
| 3267 | 3249 | } |
| 3268 | 3250 | |
| 3269 | fn allocatedSize(self: *MachO, start: u64) u64 { | |
| 3251 | pub fn allocatedSize(self: *MachO, start: u64) u64 { | |
| 3270 | 3252 | if (start == 0) return 0; |
| 3253 | ||
| 3271 | 3254 | var min_pos: u64 = std.math.maxInt(u64); |
| 3255 | ||
| 3272 | 3256 | for (self.sections.items(.header)) |header| { |
| 3273 | 3257 | if (header.offset <= start) continue; |
| 3274 | 3258 | if (header.offset < min_pos) min_pos = header.offset; |
| 3275 | 3259 | } |
| 3260 | ||
| 3276 | 3261 | for (self.segments.items) |seg| { |
| 3277 | 3262 | if (seg.fileoff <= start) continue; |
| 3278 | 3263 | if (seg.fileoff < min_pos) min_pos = seg.fileoff; |
| 3279 | 3264 | } |
| 3265 | ||
| 3280 | 3266 | return min_pos - start; |
| 3281 | 3267 | } |
| 3282 | 3268 | |
| 3283 | fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { | |
| 3269 | pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { | |
| 3284 | 3270 | if (start == 0) return 0; |
| 3271 | ||
| 3285 | 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 | 3279 | for (self.segments.items) |seg| { |
| 3287 | 3280 | if (seg.vmaddr <= start) continue; |
| 3288 | 3281 | if (seg.vmaddr < min_pos) min_pos = seg.vmaddr; |
| 3289 | 3282 | } |
| 3283 | ||
| 3290 | 3284 | return min_pos - start; |
| 3291 | 3285 | } |
| 3292 | 3286 | |
| ... | ... | @@ -3325,6 +3319,8 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64 |
| 3325 | 3319 | } |
| 3326 | 3320 | |
| 3327 | 3321 | const InitMetadataOptions = struct { |
| 3322 | emit: Compilation.Emit, | |
| 3323 | zo: *ZigObject, | |
| 3328 | 3324 | symbol_count_hint: u64, |
| 3329 | 3325 | program_code_size_hint: u64, |
| 3330 | 3326 | }; |
| ... | ... | @@ -3393,6 +3389,31 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3393 | 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 | } |
| 3397 | 3418 | |
| 3398 | 3419 | const appendSect = struct { |
| ... | ... | @@ -3470,6 +3491,44 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3470 | 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 | } |
| 3474 | 3533 | |
| 3475 | 3534 | pub 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 | 3550 | const alignment = self.getPageSize(); |
| 3492 | 3551 | const new_offset = self.findFreeSpace(needed_size, alignment); |
| 3493 | 3552 | |
| 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 | 3554 | sect.segName(), |
| 3496 | 3555 | sect.sectName(), |
| 3556 | sect.offset, | |
| 3497 | 3557 | new_offset, |
| 3498 | new_offset + existing_size, | |
| 3499 | 3558 | }); |
| 3500 | 3559 | |
| 3501 | 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 | 3616 | sect.size = needed_size; |
| 3558 | 3617 | } |
| 3559 | 3618 | |
| 3619 | pub 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 | ||
| 3560 | 3635 | pub fn getTarget(self: MachO) std.Target { |
| 3561 | 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 | 3707 | return false; |
| 3633 | 3708 | } |
| 3634 | 3709 | |
| 3710 | pub 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 | ||
| 3635 | 3725 | pub fn addSegment(self: *MachO, name: []const u8, opts: struct { |
| 3636 | 3726 | vmaddr: u64 = 0, |
| 3637 | 3727 | vmsize: u64 = 0, |
src/link/MachO/DebugSymbols.zig+35-112| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | 1 | allocator: Allocator, |
| 2 | dwarf: Dwarf, | |
| 3 | 2 | file: fs.File, |
| 4 | 3 | |
| 5 | 4 | symtab_cmd: macho.symtab_command = .{}, |
| ... | ... | @@ -17,12 +16,6 @@ debug_str_section_index: ?u8 = null, |
| 17 | 16 | debug_aranges_section_index: ?u8 = null, |
| 18 | 17 | debug_line_section_index: ?u8 = null, |
| 19 | 18 | |
| 20 | debug_string_table_dirty: bool = false, | |
| 21 | debug_abbrev_section_dirty: bool = false, | |
| 22 | debug_aranges_section_dirty: bool = false, | |
| 23 | debug_info_header_dirty: bool = false, | |
| 24 | debug_line_header_dirty: bool = false, | |
| 25 | ||
| 26 | 19 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, |
| 27 | 20 | |
| 28 | 21 | /// Output synthetic sections |
| ... | ... | @@ -44,7 +37,7 @@ pub const Reloc = struct { |
| 44 | 37 | pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void { |
| 45 | 38 | try self.strtab.append(self.allocator, 0); |
| 46 | 39 | |
| 47 | if (self.dwarf_segment_cmd_index == null) { | |
| 40 | { | |
| 48 | 41 | self.dwarf_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); |
| 49 | 42 | |
| 50 | 43 | const page_size = macho_file.getPageSize(); |
| ... | ... | @@ -63,46 +56,19 @@ pub fn initMetadata(self: *DebugSymbols, macho_file: *MachO) !void { |
| 63 | 56 | }); |
| 64 | 57 | } |
| 65 | 58 | |
| 66 | if (self.debug_str_section_index == null) { | |
| 67 | assert(self.dwarf.strtab.buffer.items.len == 0); | |
| 68 | try self.dwarf.strtab.buffer.append(self.allocator, 0); | |
| 69 | self.debug_str_section_index = try self.allocateSection( | |
| 70 | "__debug_str", | |
| 71 | @as(u32, @intCast(self.dwarf.strtab.buffer.items.len)), | |
| 72 | 0, | |
| 73 | ); | |
| 74 | self.debug_string_table_dirty = true; | |
| 75 | } | |
| 76 | ||
| 77 | if (self.debug_info_section_index == null) { | |
| 78 | self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); | |
| 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 | } | |
| 59 | self.debug_str_section_index = try self.allocateSection("__debug_str", 200, 0); | |
| 60 | self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0); | |
| 61 | self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0); | |
| 62 | self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4); | |
| 63 | self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0); | |
| 64 | ||
| 65 | self.linkedit_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); | |
| 66 | try self.segments.append(self.allocator, .{ | |
| 67 | .segname = makeStaticString("__LINKEDIT"), | |
| 68 | .maxprot = macho.PROT.READ, | |
| 69 | .initprot = macho.PROT.READ, | |
| 70 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 71 | }); | |
| 106 | 72 | } |
| 107 | 73 | |
| 108 | 74 | fn 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 | 99 | return index; |
| 134 | 100 | } |
| 135 | 101 | |
| 136 | pub fn growSection(self: *DebugSymbols, sect_index: u8, needed_size: u32, requires_file_copy: bool) !void { | |
| 102 | pub 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 | 109 | const sect = self.getSectionPtr(sect_index); |
| 138 | 110 | |
| 139 | 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 | 134 | } |
| 163 | 135 | |
| 164 | 136 | sect.size = needed_size; |
| 165 | self.markDirty(sect_index); | |
| 137 | self.markDirty(sect_index, macho_file); | |
| 166 | 138 | } |
| 167 | 139 | |
| 168 | pub fn markDirty(self: *DebugSymbols, sect_index: u8) void { | |
| 169 | if (self.debug_info_section_index.? == sect_index) { | |
| 170 | self.debug_info_header_dirty = true; | |
| 171 | } else if (self.debug_line_section_index.? == sect_index) { | |
| 172 | self.debug_line_header_dirty = true; | |
| 173 | } else if (self.debug_abbrev_section_index.? == sect_index) { | |
| 174 | self.debug_abbrev_section_dirty = true; | |
| 175 | } else if (self.debug_str_section_index.? == sect_index) { | |
| 176 | self.debug_string_table_dirty = true; | |
| 177 | } else if (self.debug_aranges_section_index.? == sect_index) { | |
| 178 | self.debug_aranges_section_dirty = true; | |
| 140 | pub fn markDirty(self: *DebugSymbols, sect_index: u8, macho_file: *MachO) void { | |
| 141 | if (macho_file.getZigObject()) |zo| { | |
| 142 | if (self.debug_info_section_index.? == sect_index) { | |
| 143 | zo.debug_info_header_dirty = true; | |
| 144 | } else if (self.debug_line_section_index.? == sect_index) { | |
| 145 | zo.debug_line_header_dirty = true; | |
| 146 | } else if (self.debug_abbrev_section_index.? == sect_index) { | |
| 147 | zo.debug_abbrev_dirty = true; | |
| 148 | } else if (self.debug_str_section_index.? == sect_index) { | |
| 149 | zo.debug_strtab_dirty = true; | |
| 150 | } else if (self.debug_aranges_section_index.? == sect_index) { | |
| 151 | zo.debug_aranges_dirty = true; | |
| 152 | } | |
| 179 | 153 | } |
| 180 | 154 | } |
| 181 | 155 | |
| ... | ... | @@ -201,13 +175,6 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 |
| 201 | 175 | } |
| 202 | 176 | |
| 203 | 177 | pub 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 | 178 | for (self.relocs.items) |*reloc| { |
| 212 | 179 | const sym = macho_file.getSymbol(reloc.target); |
| 213 | 180 | const sym_name = sym.getName(macho_file); |
| ... | ... | @@ -226,54 +193,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { |
| 226 | 193 | try self.file.pwriteAll(mem.asBytes(&addr), file_offset); |
| 227 | 194 | } |
| 228 | 195 | |
| 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 | 196 | self.finalizeDwarfSegment(macho_file); |
| 268 | 197 | try self.writeLinkeditSegmentData(macho_file); |
| 269 | 198 | |
| 270 | 199 | // Write load commands |
| 271 | 200 | const ncmds, const sizeofcmds = try self.writeLoadCommands(macho_file); |
| 272 | 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 | } |
| 278 | 203 | |
| 279 | 204 | pub fn deinit(self: *DebugSymbols) void { |
| ... | ... | @@ -281,7 +206,6 @@ pub fn deinit(self: *DebugSymbols) void { |
| 281 | 206 | self.file.close(); |
| 282 | 207 | self.segments.deinit(gpa); |
| 283 | 208 | self.sections.deinit(gpa); |
| 284 | self.dwarf.deinit(); | |
| 285 | 209 | self.relocs.deinit(gpa); |
| 286 | 210 | self.symtab.deinit(gpa); |
| 287 | 211 | self.strtab.deinit(gpa); |
| ... | ... | @@ -534,7 +458,6 @@ const padToIdeal = MachO.padToIdeal; |
| 534 | 458 | const trace = @import("../../tracy.zig").trace; |
| 535 | 459 | |
| 536 | 460 | const Allocator = mem.Allocator; |
| 537 | const Dwarf = @import("../Dwarf.zig"); | |
| 538 | 461 | const MachO = @import("../MachO.zig"); |
| 539 | 462 | const StringTable = @import("../StringTable.zig"); |
| 540 | 463 | const Type = @import("../../type.zig").Type; |
src/link/MachO/ZigObject.zig+93-13| ... | ... | @@ -46,16 +46,38 @@ tlv_initializers: TlvInitializerTable = .{}, |
| 46 | 46 | /// A table of relocations. |
| 47 | 47 | relocs: RelocationTable = .{}, |
| 48 | 48 | |
| 49 | dwarf: ?Dwarf = null, | |
| 50 | ||
| 49 | 51 | dynamic_relocs: MachO.DynamicRelocs = .{}, |
| 50 | 52 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 51 | 53 | output_ar_state: Archive.ArState = .{}, |
| 52 | 54 | |
| 55 | debug_strtab_dirty: bool = false, | |
| 56 | debug_abbrev_dirty: bool = false, | |
| 57 | debug_aranges_dirty: bool = false, | |
| 58 | debug_info_header_dirty: bool = false, | |
| 59 | debug_line_header_dirty: bool = false, | |
| 60 | ||
| 53 | 61 | pub fn init(self: *ZigObject, macho_file: *MachO) !void { |
| 54 | 62 | const comp = macho_file.base.comp; |
| 55 | 63 | const gpa = comp.gpa; |
| 56 | 64 | |
| 57 | 65 | try self.atoms.append(gpa, 0); // null input section |
| 58 | 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 | } |
| 60 | 82 | |
| 61 | 83 | pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| ... | ... | @@ -101,6 +123,10 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 101 | 123 | tlv_init.deinit(allocator); |
| 102 | 124 | } |
| 103 | 125 | self.tlv_initializers.deinit(allocator); |
| 126 | ||
| 127 | if (self.dwarf) |*dw| { | |
| 128 | dw.deinit(); | |
| 129 | } | |
| 104 | 130 | } |
| 105 | 131 | |
| 106 | 132 | fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index { |
| ... | ... | @@ -407,6 +433,66 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO) !void { |
| 407 | 433 | if (metadata.text_state != .unused) metadata.text_state = .flushed; |
| 408 | 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 | } |
| 411 | 497 | |
| 412 | 498 | pub fn getDeclVAddr( |
| ... | ... | @@ -572,7 +658,7 @@ pub fn updateFunc( |
| 572 | 658 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 573 | 659 | defer code_buffer.deinit(); |
| 574 | 660 | |
| 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 | 662 | defer if (decl_state) |*ds| ds.deinit(); |
| 577 | 663 | |
| 578 | 664 | const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none; |
| ... | ... | @@ -600,7 +686,7 @@ pub fn updateFunc( |
| 600 | 686 | |
| 601 | 687 | if (decl_state) |*ds| { |
| 602 | 688 | const sym = macho_file.getSymbol(sym_index); |
| 603 | try macho_file.getDebugSymbols().?.dwarf.commitDeclState( | |
| 689 | try self.dwarf.?.commitDeclState( | |
| 604 | 690 | mod, |
| 605 | 691 | decl_index, |
| 606 | 692 | sym.getAddress(.{}, macho_file), |
| ... | ... | @@ -647,7 +733,7 @@ pub fn updateDecl( |
| 647 | 733 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 648 | 734 | defer code_buffer.deinit(); |
| 649 | 735 | |
| 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 | 737 | defer if (decl_state) |*ds| ds.deinit(); |
| 652 | 738 | |
| 653 | 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 | 767 | |
| 682 | 768 | if (decl_state) |*ds| { |
| 683 | 769 | const sym = macho_file.getSymbol(sym_index); |
| 684 | try macho_file.getDebugSymbols().?.dwarf.commitDeclState( | |
| 770 | try self.dwarf.?.commitDeclState( | |
| 685 | 771 | mod, |
| 686 | 772 | decl_index, |
| 687 | 773 | sym.getAddress(.{}, macho_file), |
| ... | ... | @@ -1257,15 +1343,9 @@ fn updateLazySymbol( |
| 1257 | 1343 | } |
| 1258 | 1344 | |
| 1259 | 1345 | /// Must be called only after a successful call to `updateDecl`. |
| 1260 | pub fn updateDeclLineNumber( | |
| 1261 | self: *ZigObject, | |
| 1262 | macho_file: *MachO, | |
| 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); | |
| 1346 | pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void { | |
| 1347 | if (self.dwarf) |*dw| { | |
| 1348 | try dw.updateDeclLineNumber(mod, decl_index); | |
| 1269 | 1349 | } |
| 1270 | 1350 | } |
| 1271 | 1351 |
src/link/MachO/relocatable.zig+21-19| ... | ... | @@ -193,8 +193,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 193 | 193 | // Update file offsets of contributing objects |
| 194 | 194 | const total_size: usize = blk: { |
| 195 | 195 | var pos: usize = Archive.SARMAG; |
| 196 | pos += @sizeOf(Archive.ar_hdr) + Archive.SYMDEF.len + 1; | |
| 197 | pos = mem.alignForward(usize, pos, ptr_width); | |
| 196 | pos += @sizeOf(Archive.ar_hdr); | |
| 197 | pos += mem.alignForward(usize, Archive.SYMDEF.len + 1, ptr_width); | |
| 198 | 198 | pos += ar_symtab.size(format); |
| 199 | 199 | |
| 200 | 200 | for (files.items) |index| { |
| ... | ... | @@ -209,10 +209,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 209 | 209 | .object => |x| x.path, |
| 210 | 210 | else => unreachable, |
| 211 | 211 | }; |
| 212 | pos = mem.alignForward(usize, pos, ptr_width); | |
| 212 | pos = mem.alignForward(usize, pos, 2); | |
| 213 | 213 | state.file_off = pos; |
| 214 | pos += @sizeOf(Archive.ar_hdr) + path.len + 1; | |
| 215 | pos = mem.alignForward(usize, pos, ptr_width); | |
| 214 | pos += @sizeOf(Archive.ar_hdr); | |
| 215 | pos += mem.alignForward(usize, path.len + 1, ptr_width); | |
| 216 | 216 | pos += math.cast(usize, state.size) orelse return error.Overflow; |
| 217 | 217 | } |
| 218 | 218 | |
| ... | ... | @@ -236,7 +236,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 236 | 236 | |
| 237 | 237 | // Write object files |
| 238 | 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 | 240 | const padding = aligned - buffer.items.len; |
| 241 | 241 | if (padding > 0) { |
| 242 | 242 | try writer.writeByteNTimes(0, padding); |
| ... | ... | @@ -402,7 +402,7 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 402 | 402 | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 403 | 403 | if (!atom.flags.alive) continue; |
| 404 | 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 | 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 | 436 | |
| 437 | 437 | fn allocateSections(macho_file: *MachO) !void { |
| 438 | 438 | const slice = macho_file.sections.slice(); |
| 439 | ||
| 440 | const last_index = for (0..slice.items(.header).len) |i| { | |
| 441 | if (macho_file.isZigSection(@intCast(i))) break i; | |
| 442 | } else slice.items(.header).len; | |
| 443 | ||
| 444 | for (slice.items(.header)[0..last_index]) |*header| { | |
| 439 | for (slice.items(.header)) |*header| { | |
| 440 | const needed_size = header.size; | |
| 441 | header.size = 0; | |
| 445 | 442 | const alignment = try math.powi(u32, 2, header.@"align"); |
| 446 | 443 | if (!header.isZerofill()) { |
| 447 | header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse | |
| 448 | return error.Overflow; | |
| 444 | if (needed_size > macho_file.allocatedSize(header.offset)) { | |
| 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 | } |
| 453 | 455 | |
| ... | ... | @@ -539,7 +541,7 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 539 | 541 | for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { |
| 540 | 542 | if (atoms.items.len == 0) continue; |
| 541 | 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; | |
| 543 | 545 | |
| 544 | 546 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 545 | 547 | const code = try gpa.alloc(u8, size); |
| ... | ... | @@ -580,7 +582,7 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 580 | 582 | |
| 581 | 583 | for (macho_file.sections.items(.header), 0..) |header, n_sect| { |
| 582 | 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 | 586 | const gop = try relocs.getOrPut(@intCast(n_sect)); |
| 585 | 587 | if (gop.found_existing) continue; |
| 586 | 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 | 593 | if (!atom.flags.alive) continue; |
| 592 | 594 | const header = macho_file.sections.items(.header)[atom.out_n_sect]; |
| 593 | 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 | 597 | if (atom.getRelocs(macho_file).len == 0) continue; |
| 596 | 598 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 597 | 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 | 20 | }; |
| 21 | 21 | |
| 22 | 22 | // Exercise linker with self-hosted backend (no LLVM) |
| 23 | macho_step.dependOn(testEmptyZig(b, .{ .use_llvm = false, .target = x86_64_target })); | |
| 23 | 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 })); | |
| 25 | 28 | |
| 26 | 29 | // Exercise linker with LLVM backend |
| 27 | 30 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); |
| ... | ... | @@ -33,6 +36,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 33 | 36 | macho_step.dependOn(testHelloZig(b, .{ .target = default_target })); |
| 34 | 37 | macho_step.dependOn(testLargeBss(b, .{ .target = default_target })); |
| 35 | 38 | macho_step.dependOn(testLayout(b, .{ .target = default_target })); |
| 39 | macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target })); | |
| 36 | 40 | macho_step.dependOn(testLinksection(b, .{ .target = default_target })); |
| 37 | 41 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); |
| 38 | 42 | macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target })); |
| ... | ... | @@ -843,6 +847,45 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step { |
| 843 | 847 | return test_step; |
| 844 | 848 | } |
| 845 | 849 | |
| 850 | fn 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 | ||
| 846 | 889 | fn testLinksection(b: *Build, opts: Options) *Step { |
| 847 | 890 | const test_step = addTestStep(b, "macho-linksection", opts); |
| 848 | 891 | |
| ... | ... | @@ -1243,14 +1286,7 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step { |
| 1243 | 1286 | const run = addRunArtifact(exe); |
| 1244 | 1287 | run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") }); |
| 1245 | 1288 | run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") }); |
| 1246 | if (opts.use_llvm) { | |
| 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 | } | |
| 1289 | run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") }); | |
| 1254 | 1290 | test_step.dependOn(&run.step); |
| 1255 | 1291 | |
| 1256 | 1292 | return test_step; |