| author | |
| committer | |
| log | acd700ac6b4ec03412e2bac6aaf168f80f83f521 |
| tree | 15c00fc6dfb8d7cd3fd9e7d2f53f460877ca6067 |
| parent | ed2984f335bfaf7cc3cb7841554f4cbb958476dd |
4 files changed, 347 insertions(+), 243 deletions(-)
src/link/Elf.zig+42-177| ... | ... | @@ -186,12 +186,6 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{} |
| 186 | 186 | /// such as `resolver` and `comdat_groups_table`. |
| 187 | 187 | strings: StringTable = .{}, |
| 188 | 188 | |
| 189 | /// Static archive state. | |
| 190 | /// TODO it may be wise to move it somewhere else, but for the time being, it | |
| 191 | /// is far easier to pollute global state. | |
| 192 | ar_symtab: std.ArrayListUnmanaged(ArSymtabEntry) = .{}, | |
| 193 | ar_strtab: StringTable = .{}, | |
| 194 | ||
| 195 | 189 | /// When allocating, the ideal_capacity is calculated by |
| 196 | 190 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 197 | 191 | const ideal_factor = 3; |
| ... | ... | @@ -398,9 +392,6 @@ pub fn deinit(self: *Elf) void { |
| 398 | 392 | self.copy_rel.deinit(gpa); |
| 399 | 393 | self.rela_dyn.deinit(gpa); |
| 400 | 394 | self.rela_plt.deinit(gpa); |
| 401 | ||
| 402 | self.ar_symtab.deinit(gpa); | |
| 403 | self.ar_strtab.deinit(gpa); | |
| 404 | 395 | } |
| 405 | 396 | |
| 406 | 397 | pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { |
| ... | ... | @@ -1553,175 +1544,74 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void |
| 1553 | 1544 | try self.writeSymtab(); |
| 1554 | 1545 | try self.writeShStrtab(); |
| 1555 | 1546 | try self.writeElfHeader(); |
| 1556 | ||
| 1557 | // Update ar symbol table. | |
| 1558 | try zig_object.asFile().updateArSymtab(self); | |
| 1559 | 1547 | } |
| 1560 | 1548 | |
| 1561 | 1549 | // TODO parse positionals that we want to make part of the archive |
| 1562 | 1550 | |
| 1563 | mem.sort(ArSymtabEntry, self.ar_symtab.items, {}, ArSymtabEntry.lessThan); | |
| 1551 | // TODO update ar symtab from parsed positionals | |
| 1564 | 1552 | |
| 1565 | if (build_options.enable_logging) { | |
| 1566 | state_log.debug("{}", .{self.dumpState()}); | |
| 1567 | } | |
| 1568 | ||
| 1569 | // Save object paths in filenames strtab. | |
| 1570 | var ar_strtab = std.ArrayList(u8).init(gpa); | |
| 1571 | defer ar_strtab.deinit(); | |
| 1572 | ||
| 1573 | var files = std.AutoHashMap(File.Index, struct { u32, u64, u64 }).init(gpa); | |
| 1574 | defer files.deinit(); | |
| 1575 | try files.ensureUnusedCapacity(@intCast(self.objects.items.len + 1)); | |
| 1553 | var ar_symtab: Archive.ArSymtab = .{}; | |
| 1554 | defer ar_symtab.deinit(gpa); | |
| 1576 | 1555 | |
| 1577 | 1556 | if (self.zigObjectPtr()) |zig_object| { |
| 1578 | const off = @as(u32, @intCast(ar_strtab.items.len)); | |
| 1579 | try ar_strtab.writer().print("{s}/\n", .{zig_object.path}); | |
| 1580 | files.putAssumeCapacityNoClobber(zig_object.index, .{ off, 0, 0 }); | |
| 1581 | } | |
| 1582 | ||
| 1583 | // Align to even byte boundary | |
| 1584 | { | |
| 1585 | const end = ar_strtab.items.len; | |
| 1586 | const aligned = mem.alignForward(usize, end, 2); | |
| 1587 | try ar_strtab.writer().writeByteNTimes(0, aligned - end); | |
| 1557 | try zig_object.updateArSymtab(&ar_symtab, self); | |
| 1588 | 1558 | } |
| 1589 | 1559 | |
| 1590 | // Encode ar symtab in 64bit format. | |
| 1591 | var ar_symtab = std.ArrayList(u8).init(gpa); | |
| 1592 | defer ar_symtab.deinit(); | |
| 1593 | try ar_symtab.ensureUnusedCapacity(8 * (self.ar_symtab.items.len + 1)); | |
| 1594 | ||
| 1595 | // Number of symbols | |
| 1596 | ar_symtab.writer().writeInt(u64, @as(u64, @intCast(self.ar_symtab.items.len)), .big) catch unreachable; | |
| 1560 | ar_symtab.sort(); | |
| 1597 | 1561 | |
| 1598 | // Offsets which we will relocate later. | |
| 1599 | for (0..self.ar_symtab.items.len) |_| { | |
| 1600 | ar_symtab.writer().writeInt(u64, 0, .big) catch unreachable; | |
| 1601 | } | |
| 1562 | // Save object paths in filenames strtab. | |
| 1563 | var ar_strtab: Archive.ArStrtab = .{}; | |
| 1564 | defer ar_strtab.deinit(gpa); | |
| 1602 | 1565 | |
| 1603 | // ASCII offsets into the strtab. | |
| 1604 | for (self.ar_symtab.items) |entry| { | |
| 1605 | const name = self.ar_strtab.getAssumeExists(entry.off); | |
| 1606 | try ar_symtab.writer().print("{s}\x00", .{name}); | |
| 1566 | if (self.zigObjectPtr()) |zig_object| { | |
| 1567 | try zig_object.updateArStrtab(gpa, &ar_strtab); | |
| 1568 | zig_object.updateArSize(self); | |
| 1607 | 1569 | } |
| 1608 | 1570 | |
| 1609 | // Align to 8 bytes if required | |
| 1610 | { | |
| 1611 | const end = ar_symtab.items.len; | |
| 1612 | const aligned = mem.alignForward(usize, end, 8); | |
| 1613 | try ar_symtab.writer().writeByteNTimes(0, aligned - end); | |
| 1614 | } | |
| 1571 | // Update file offsets of contributing objects. | |
| 1572 | const total_size: u64 = blk: { | |
| 1573 | var pos: u64 = Archive.SARMAG; | |
| 1574 | pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64); | |
| 1575 | pos = mem.alignForward(u64, pos, 2); | |
| 1576 | pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size(); | |
| 1615 | 1577 | |
| 1616 | assert(mem.isAligned(ar_symtab.items.len, 8)); | |
| 1578 | if (self.zigObjectPtr()) |zig_object| { | |
| 1579 | pos = mem.alignForward(u64, pos, 2); | |
| 1580 | zig_object.output_ar_state.file_off = pos; | |
| 1581 | pos += @sizeOf(Archive.ar_hdr) + zig_object.output_ar_state.size; | |
| 1582 | } | |
| 1617 | 1583 | |
| 1618 | // Calculate required size for headers before ZigObject pos in file. | |
| 1619 | if (self.zigObjectPtr()) |zig_object| { | |
| 1620 | var file_off: u64 = 0; | |
| 1621 | // Magic | |
| 1622 | file_off += Archive.SARMAG; | |
| 1623 | // Symtab | |
| 1624 | file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_symtab.items.len)); | |
| 1625 | // Strtab | |
| 1626 | file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_strtab.items.len)); | |
| 1627 | ||
| 1628 | const files_ptr = files.getPtr(zig_object.index).?; | |
| 1629 | files_ptr[1] = file_off; | |
| 1630 | ||
| 1631 | // Move ZigObject into place. | |
| 1632 | { | |
| 1633 | var end_pos: u64 = self.shdr_table_offset.?; | |
| 1634 | for (self.shdrs.items) |shdr| { | |
| 1635 | end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size); | |
| 1636 | } | |
| 1637 | const contents = try gpa.alloc(u8, end_pos); | |
| 1638 | defer gpa.free(contents); | |
| 1639 | const amt = try self.base.file.?.preadAll(contents, 0); | |
| 1640 | if (amt != end_pos) return error.InputOutput; | |
| 1641 | try self.base.file.?.pwriteAll(contents, file_off + @sizeOf(Archive.ar_hdr)); | |
| 1584 | break :blk pos; | |
| 1585 | }; | |
| 1642 | 1586 | |
| 1643 | files_ptr[2] = end_pos; | |
| 1644 | } | |
| 1587 | if (build_options.enable_logging) { | |
| 1588 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); | |
| 1589 | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); | |
| 1645 | 1590 | } |
| 1646 | 1591 | |
| 1647 | // Fixup file offsets in the symtab. | |
| 1648 | for (self.ar_symtab.items, 1..) |entry, i| { | |
| 1649 | const file_off = files.get(entry.file_index).?[1]; | |
| 1650 | mem.writeInt(u64, ar_symtab.items[8 * i ..][0..8], file_off, .big); | |
| 1651 | } | |
| 1592 | var buffer = std.ArrayList(u8).init(gpa); | |
| 1593 | defer buffer.deinit(); | |
| 1594 | try buffer.ensureTotalCapacityPrecise(total_size); | |
| 1652 | 1595 | |
| 1653 | var pos: usize = Archive.SARMAG; | |
| 1596 | // Write magic | |
| 1597 | try buffer.writer().writeAll(Archive.ARMAG); | |
| 1654 | 1598 | |
| 1655 | // Write symtab. | |
| 1656 | { | |
| 1657 | const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar_symtab.items.len) }); | |
| 1658 | try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos); | |
| 1659 | pos += @sizeOf(Archive.ar_hdr); | |
| 1660 | try self.base.file.?.pwriteAll(ar_symtab.items, pos); | |
| 1661 | pos += ar_symtab.items.len; | |
| 1662 | } | |
| 1599 | // Write symtab | |
| 1600 | try ar_symtab.write(.p64, self, buffer.writer()); | |
| 1601 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | |
| 1663 | 1602 | |
| 1664 | // Write strtab. | |
| 1665 | { | |
| 1666 | const hdr = setArHdr(.{ | |
| 1667 | .kind = .strtab, | |
| 1668 | .name_off = 0, | |
| 1669 | .size = @intCast(ar_strtab.items.len), | |
| 1670 | }); | |
| 1671 | try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos); | |
| 1672 | pos += @sizeOf(Archive.ar_hdr); | |
| 1673 | try self.base.file.?.pwriteAll(ar_strtab.items, pos); | |
| 1674 | pos += ar_strtab.items.len; | |
| 1675 | } | |
| 1603 | // Write strtab | |
| 1604 | try ar_strtab.write(buffer.writer()); | |
| 1605 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | |
| 1676 | 1606 | |
| 1677 | // Zig object if defined | |
| 1607 | // Write object files | |
| 1678 | 1608 | if (self.zigObjectPtr()) |zig_object| { |
| 1679 | const entry = files.get(zig_object.index).?; | |
| 1680 | const hdr = setArHdr(.{ .kind = .object, .name_off = entry[0], .size = @intCast(entry[2]) }); | |
| 1681 | try self.base.file.?.pwriteAll(mem.asBytes(&hdr), entry[1]); | |
| 1682 | pos += @sizeOf(Archive.ar_hdr) + entry[2]; | |
| 1609 | try zig_object.writeAr(self, buffer.writer()); | |
| 1683 | 1610 | } |
| 1684 | 1611 | |
| 1685 | // TODO parsed positionals | |
| 1612 | assert(buffer.items.len == total_size); | |
| 1686 | 1613 | |
| 1687 | // Magic bytes. | |
| 1688 | { | |
| 1689 | try self.base.file.?.pwriteAll(Archive.ARMAG, 0); | |
| 1690 | } | |
| 1691 | } | |
| 1692 | ||
| 1693 | fn setArHdr(opts: struct { | |
| 1694 | kind: enum { symtab, strtab, object }, | |
| 1695 | name_off: u32, | |
| 1696 | size: u32, | |
| 1697 | }) Archive.ar_hdr { | |
| 1698 | var hdr: Archive.ar_hdr = .{ | |
| 1699 | .ar_name = undefined, | |
| 1700 | .ar_date = undefined, | |
| 1701 | .ar_uid = undefined, | |
| 1702 | .ar_gid = undefined, | |
| 1703 | .ar_mode = undefined, | |
| 1704 | .ar_size = undefined, | |
| 1705 | .ar_fmag = undefined, | |
| 1706 | }; | |
| 1707 | @memset(mem.asBytes(&hdr), 0x20); | |
| 1708 | @memcpy(&hdr.ar_fmag, Archive.ARFMAG); | |
| 1709 | ||
| 1710 | { | |
| 1711 | var stream = std.io.fixedBufferStream(&hdr.ar_name); | |
| 1712 | const writer = stream.writer(); | |
| 1713 | switch (opts.kind) { | |
| 1714 | .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, | |
| 1715 | .strtab => writer.print("//", .{}) catch unreachable, | |
| 1716 | .object => writer.print("/{d}", .{opts.name_off}) catch unreachable, | |
| 1717 | } | |
| 1718 | } | |
| 1719 | { | |
| 1720 | var stream = std.io.fixedBufferStream(&hdr.ar_size); | |
| 1721 | stream.writer().print("{d}", .{opts.size}) catch unreachable; | |
| 1722 | } | |
| 1723 | ||
| 1724 | return hdr; | |
| 1614 | try self.base.file.?.pwriteAll(buffer.items, 0); | |
| 1725 | 1615 | } |
| 1726 | 1616 | |
| 1727 | 1617 | pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void { |
| ... | ... | @@ -5822,18 +5712,6 @@ fn fmtDumpState( |
| 5822 | 5712 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| 5823 | 5713 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); |
| 5824 | 5714 | |
| 5825 | if (self.isStaticLib()) { | |
| 5826 | try writer.writeAll("ar symtab\n"); | |
| 5827 | for (self.ar_symtab.items, 0..) |entry, i| { | |
| 5828 | try writer.print(" {d} : {s} in file({d})\n", .{ | |
| 5829 | i, | |
| 5830 | self.ar_strtab.getAssumeExists(entry.off), | |
| 5831 | entry.file_index, | |
| 5832 | }); | |
| 5833 | } | |
| 5834 | try writer.writeByte('\n'); | |
| 5835 | } | |
| 5836 | ||
| 5837 | 5715 | try writer.writeAll("Output shdrs\n"); |
| 5838 | 5716 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 5839 | 5717 | try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{ |
| ... | ... | @@ -5966,19 +5844,6 @@ const LastAtomAndFreeList = struct { |
| 5966 | 5844 | |
| 5967 | 5845 | const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList); |
| 5968 | 5846 | |
| 5969 | const ArSymtabEntry = struct { | |
| 5970 | off: u32, | |
| 5971 | file_index: File.Index, | |
| 5972 | ||
| 5973 | pub fn lessThan(ctx: void, lhs: ArSymtabEntry, rhs: ArSymtabEntry) bool { | |
| 5974 | _ = ctx; | |
| 5975 | if (lhs.off == rhs.off) { | |
| 5976 | return lhs.file_index < rhs.file_index; | |
| 5977 | } | |
| 5978 | return lhs.off < rhs.off; | |
| 5979 | } | |
| 5980 | }; | |
| 5981 | ||
| 5982 | 5847 | pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1; |
| 5983 | 5848 | pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2; |
| 5984 | 5849 |
src/link/Elf/Archive.zig+262-60| ... | ... | @@ -4,69 +4,11 @@ data: []const u8, |
| 4 | 4 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 5 | 5 | strtab: []const u8 = &[0]u8{}, |
| 6 | 6 | |
| 7 | // Archive files start with the ARMAG identifying string. Then follows a | |
| 8 | // `struct ar_hdr', and as many bytes of member file data as its `ar_size' | |
| 9 | // member indicates, for each member file. | |
| 10 | /// String that begins an archive file. | |
| 11 | pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; | |
| 12 | /// Size of that string. | |
| 13 | pub const SARMAG = 8; | |
| 14 | ||
| 15 | /// String in ar_fmag at the end of each header. | |
| 16 | pub const ARFMAG: *const [2:0]u8 = "`\n"; | |
| 17 | ||
| 18 | pub const SYM64NAME: *const [7:0]u8 = "/SYM64/"; | |
| 19 | ||
| 20 | pub const ar_hdr = extern struct { | |
| 21 | /// Member file name, sometimes / terminated. | |
| 22 | ar_name: [16]u8, | |
| 23 | ||
| 24 | /// File date, decimal seconds since Epoch. | |
| 25 | ar_date: [12]u8, | |
| 26 | ||
| 27 | /// User ID, in ASCII format. | |
| 28 | ar_uid: [6]u8, | |
| 29 | ||
| 30 | /// Group ID, in ASCII format. | |
| 31 | ar_gid: [6]u8, | |
| 32 | ||
| 33 | /// File mode, in ASCII octal. | |
| 34 | ar_mode: [8]u8, | |
| 35 | ||
| 36 | /// File size, in ASCII decimal. | |
| 37 | ar_size: [10]u8, | |
| 38 | ||
| 39 | /// Always contains ARFMAG. | |
| 40 | ar_fmag: [2]u8, | |
| 41 | ||
| 42 | fn date(self: ar_hdr) !u64 { | |
| 43 | const value = getValue(&self.ar_date); | |
| 44 | return std.fmt.parseInt(u64, value, 10); | |
| 45 | } | |
| 46 | ||
| 47 | fn size(self: ar_hdr) !u32 { | |
| 48 | const value = getValue(&self.ar_size); | |
| 49 | return std.fmt.parseInt(u32, value, 10); | |
| 50 | } | |
| 51 | ||
| 52 | fn getValue(raw: []const u8) []const u8 { | |
| 53 | return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)}); | |
| 54 | } | |
| 55 | ||
| 56 | fn isStrtab(self: ar_hdr) bool { | |
| 57 | return mem.eql(u8, getValue(&self.ar_name), "//"); | |
| 58 | } | |
| 59 | ||
| 60 | fn isSymtab(self: ar_hdr) bool { | |
| 61 | return mem.eql(u8, getValue(&self.ar_name), "/") or mem.eql(u8, getValue(&self.ar_name), SYM64NAME); | |
| 62 | } | |
| 63 | }; | |
| 64 | ||
| 65 | 7 | pub fn isArchive(path: []const u8) !bool { |
| 66 | 8 | const file = try std.fs.cwd().openFile(path, .{}); |
| 67 | 9 | defer file.close(); |
| 68 | 10 | const reader = file.reader(); |
| 69 | const magic = reader.readBytesNoEof(Archive.SARMAG) catch return false; | |
| 11 | const magic = reader.readBytesNoEof(SARMAG) catch return false; | |
| 70 | 12 | if (!mem.eql(u8, &magic, ARMAG)) return false; |
| 71 | 13 | return true; |
| 72 | 14 | } |
| ... | ... | @@ -140,9 +82,267 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { |
| 140 | 82 | |
| 141 | 83 | fn getString(self: Archive, off: u32) []const u8 { |
| 142 | 84 | assert(off < self.strtab.len); |
| 143 | return mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); | |
| 85 | return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn setArHdr(opts: struct { | |
| 89 | kind: enum { symtab, strtab, object }, | |
| 90 | name_off: u32, | |
| 91 | size: u32, | |
| 92 | }) ar_hdr { | |
| 93 | var hdr: ar_hdr = .{ | |
| 94 | .ar_name = undefined, | |
| 95 | .ar_date = undefined, | |
| 96 | .ar_uid = undefined, | |
| 97 | .ar_gid = undefined, | |
| 98 | .ar_mode = undefined, | |
| 99 | .ar_size = undefined, | |
| 100 | .ar_fmag = undefined, | |
| 101 | }; | |
| 102 | @memset(mem.asBytes(&hdr), 0x20); | |
| 103 | @memcpy(&hdr.ar_fmag, Archive.ARFMAG); | |
| 104 | ||
| 105 | { | |
| 106 | var stream = std.io.fixedBufferStream(&hdr.ar_name); | |
| 107 | const writer = stream.writer(); | |
| 108 | switch (opts.kind) { | |
| 109 | .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, | |
| 110 | .strtab => writer.print("//", .{}) catch unreachable, | |
| 111 | .object => writer.print("/{d}", .{opts.name_off}) catch unreachable, | |
| 112 | } | |
| 113 | } | |
| 114 | { | |
| 115 | var stream = std.io.fixedBufferStream(&hdr.ar_size); | |
| 116 | stream.writer().print("{d}", .{opts.size}) catch unreachable; | |
| 117 | } | |
| 118 | ||
| 119 | return hdr; | |
| 144 | 120 | } |
| 145 | 121 | |
| 122 | // Archive files start with the ARMAG identifying string. Then follows a | |
| 123 | // `struct ar_hdr', and as many bytes of member file data as its `ar_size' | |
| 124 | // member indicates, for each member file. | |
| 125 | /// String that begins an archive file. | |
| 126 | pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; | |
| 127 | /// Size of that string. | |
| 128 | pub const SARMAG = 8; | |
| 129 | ||
| 130 | /// String in ar_fmag at the end of each header. | |
| 131 | const ARFMAG: *const [2:0]u8 = "`\n"; | |
| 132 | ||
| 133 | /// Strtab identifier | |
| 134 | const STRNAME: *const [2:0]u8 = "//"; | |
| 135 | ||
| 136 | /// 32-bit symtab identifier | |
| 137 | const SYMNAME: *const [1:0]u8 = "/"; | |
| 138 | ||
| 139 | /// 64-bit symtab identifier | |
| 140 | const SYM64NAME: *const [7:0]u8 = "/SYM64/"; | |
| 141 | ||
| 142 | const strtab_delimiter = '\n'; | |
| 143 | ||
| 144 | pub const ar_hdr = extern struct { | |
| 145 | /// Member file name, sometimes / terminated. | |
| 146 | ar_name: [16]u8, | |
| 147 | ||
| 148 | /// File date, decimal seconds since Epoch. | |
| 149 | ar_date: [12]u8, | |
| 150 | ||
| 151 | /// User ID, in ASCII format. | |
| 152 | ar_uid: [6]u8, | |
| 153 | ||
| 154 | /// Group ID, in ASCII format. | |
| 155 | ar_gid: [6]u8, | |
| 156 | ||
| 157 | /// File mode, in ASCII octal. | |
| 158 | ar_mode: [8]u8, | |
| 159 | ||
| 160 | /// File size, in ASCII decimal. | |
| 161 | ar_size: [10]u8, | |
| 162 | ||
| 163 | /// Always contains ARFMAG. | |
| 164 | ar_fmag: [2]u8, | |
| 165 | ||
| 166 | fn date(self: ar_hdr) !u64 { | |
| 167 | const value = getValue(&self.ar_date); | |
| 168 | return std.fmt.parseInt(u64, value, 10); | |
| 169 | } | |
| 170 | ||
| 171 | fn size(self: ar_hdr) !u32 { | |
| 172 | const value = getValue(&self.ar_size); | |
| 173 | return std.fmt.parseInt(u32, value, 10); | |
| 174 | } | |
| 175 | ||
| 176 | fn getValue(raw: []const u8) []const u8 { | |
| 177 | return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)}); | |
| 178 | } | |
| 179 | ||
| 180 | fn isStrtab(self: ar_hdr) bool { | |
| 181 | return mem.eql(u8, getValue(&self.ar_name), STRNAME); | |
| 182 | } | |
| 183 | ||
| 184 | fn isSymtab(self: ar_hdr) bool { | |
| 185 | return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME); | |
| 186 | } | |
| 187 | }; | |
| 188 | ||
| 189 | pub const ArSymtab = struct { | |
| 190 | symtab: std.ArrayListUnmanaged(Entry) = .{}, | |
| 191 | strtab: StringTable = .{}, | |
| 192 | ||
| 193 | pub fn deinit(ar: *ArSymtab, allocator: Allocator) void { | |
| 194 | ar.symtab.deinit(allocator); | |
| 195 | ar.strtab.deinit(allocator); | |
| 196 | } | |
| 197 | ||
| 198 | pub fn sort(ar: *ArSymtab) void { | |
| 199 | mem.sort(Entry, ar.symtab.items, {}, Entry.lessThan); | |
| 200 | } | |
| 201 | ||
| 202 | pub fn size(ar: ArSymtab, kind: enum { p32, p64 }) usize { | |
| 203 | const ptr_size: usize = switch (kind) { | |
| 204 | .p32 => 4, | |
| 205 | .p64 => 8, | |
| 206 | }; | |
| 207 | var ss: usize = ptr_size + ar.symtab.items.len * ptr_size; | |
| 208 | for (ar.symtab.items) |entry| { | |
| 209 | ss += ar.strtab.getAssumeExists(entry.off).len + 1; | |
| 210 | } | |
| 211 | return ss; | |
| 212 | } | |
| 213 | ||
| 214 | pub fn write(ar: ArSymtab, kind: enum { p32, p64 }, elf_file: *Elf, writer: anytype) !void { | |
| 215 | assert(kind == .p64); // TODO p32 | |
| 216 | const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar.size(.p64)) }); | |
| 217 | try writer.writeAll(mem.asBytes(&hdr)); | |
| 218 | ||
| 219 | const gpa = elf_file.base.allocator; | |
| 220 | var offsets = std.AutoHashMap(File.Index, u64).init(gpa); | |
| 221 | defer offsets.deinit(); | |
| 222 | try offsets.ensureUnusedCapacity(@intCast(elf_file.objects.items.len + 1)); | |
| 223 | ||
| 224 | if (elf_file.zigObjectPtr()) |zig_object| { | |
| 225 | offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off); | |
| 226 | } | |
| 227 | ||
| 228 | // Number of symbols | |
| 229 | try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big); | |
| 230 | ||
| 231 | // Offsets to files | |
| 232 | for (ar.symtab.items) |entry| { | |
| 233 | const off = offsets.get(entry.file_index).?; | |
| 234 | try writer.writeInt(u64, off, .big); | |
| 235 | } | |
| 236 | ||
| 237 | // Strings | |
| 238 | for (ar.symtab.items) |entry| { | |
| 239 | try writer.print("{s}\x00", .{ar.strtab.getAssumeExists(entry.off)}); | |
| 240 | } | |
| 241 | } | |
| 242 | ||
| 243 | pub fn format( | |
| 244 | ar: ArSymtab, | |
| 245 | comptime unused_fmt_string: []const u8, | |
| 246 | options: std.fmt.FormatOptions, | |
| 247 | writer: anytype, | |
| 248 | ) !void { | |
| 249 | _ = ar; | |
| 250 | _ = unused_fmt_string; | |
| 251 | _ = options; | |
| 252 | _ = writer; | |
| 253 | @compileError("do not format ar symtab directly; use fmt instead"); | |
| 254 | } | |
| 255 | ||
| 256 | const FormatContext = struct { | |
| 257 | ar: ArSymtab, | |
| 258 | elf_file: *Elf, | |
| 259 | }; | |
| 260 | ||
| 261 | pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(format2) { | |
| 262 | return .{ .data = .{ | |
| 263 | .ar = ar, | |
| 264 | .elf_file = elf_file, | |
| 265 | } }; | |
| 266 | } | |
| 267 | ||
| 268 | fn format2( | |
| 269 | ctx: FormatContext, | |
| 270 | comptime unused_fmt_string: []const u8, | |
| 271 | options: std.fmt.FormatOptions, | |
| 272 | writer: anytype, | |
| 273 | ) !void { | |
| 274 | _ = unused_fmt_string; | |
| 275 | _ = options; | |
| 276 | const ar = ctx.ar; | |
| 277 | const elf_file = ctx.elf_file; | |
| 278 | for (ar.symtab.items, 0..) |entry, i| { | |
| 279 | const name = ar.strtab.getAssumeExists(entry.off); | |
| 280 | const file = elf_file.file(entry.file_index).?; | |
| 281 | try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() }); | |
| 282 | } | |
| 283 | } | |
| 284 | ||
| 285 | const Entry = struct { | |
| 286 | /// Offset into the string table. | |
| 287 | off: u32, | |
| 288 | /// Index of the file defining the global. | |
| 289 | file_index: File.Index, | |
| 290 | ||
| 291 | pub fn lessThan(ctx: void, lhs: Entry, rhs: Entry) bool { | |
| 292 | _ = ctx; | |
| 293 | if (lhs.off == rhs.off) return lhs.file_index < rhs.file_index; | |
| 294 | return lhs.off < rhs.off; | |
| 295 | } | |
| 296 | }; | |
| 297 | }; | |
| 298 | ||
| 299 | pub const ArStrtab = struct { | |
| 300 | buffer: std.ArrayListUnmanaged(u8) = .{}, | |
| 301 | ||
| 302 | pub fn deinit(ar: *ArStrtab, allocator: Allocator) void { | |
| 303 | ar.buffer.deinit(allocator); | |
| 304 | } | |
| 305 | ||
| 306 | pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 { | |
| 307 | const off = @as(u32, @intCast(ar.buffer.items.len)); | |
| 308 | try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter }); | |
| 309 | return off; | |
| 310 | } | |
| 311 | ||
| 312 | pub fn size(ar: ArStrtab) usize { | |
| 313 | return ar.buffer.items.len; | |
| 314 | } | |
| 315 | ||
| 316 | pub fn write(ar: ArStrtab, writer: anytype) !void { | |
| 317 | const hdr = setArHdr(.{ .kind = .strtab, .name_off = 0, .size = @intCast(ar.size()) }); | |
| 318 | try writer.writeAll(mem.asBytes(&hdr)); | |
| 319 | try writer.writeAll(ar.buffer.items); | |
| 320 | } | |
| 321 | ||
| 322 | pub fn format( | |
| 323 | ar: ArStrtab, | |
| 324 | comptime unused_fmt_string: []const u8, | |
| 325 | options: std.fmt.FormatOptions, | |
| 326 | writer: anytype, | |
| 327 | ) !void { | |
| 328 | _ = unused_fmt_string; | |
| 329 | _ = options; | |
| 330 | try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); | |
| 331 | } | |
| 332 | }; | |
| 333 | ||
| 334 | pub const ArState = struct { | |
| 335 | /// Name offset in the string table. | |
| 336 | name_off: u32 = 0, | |
| 337 | ||
| 338 | /// File offset of the ar_hdr describing the contributing | |
| 339 | /// object in the archive. | |
| 340 | file_off: u64 = 0, | |
| 341 | ||
| 342 | /// Total size of the contributing object (excludes ar_hdr). | |
| 343 | size: u64 = 0, | |
| 344 | }; | |
| 345 | ||
| 146 | 346 | const std = @import("std"); |
| 147 | 347 | const assert = std.debug.assert; |
| 148 | 348 | const elf = std.elf; |
| ... | ... | @@ -153,4 +353,6 @@ const mem = std.mem; |
| 153 | 353 | const Allocator = mem.Allocator; |
| 154 | 354 | const Archive = @This(); |
| 155 | 355 | const Elf = @import("../Elf.zig"); |
| 356 | const File = @import("file.zig").File; | |
| 156 | 357 | const Object = @import("Object.zig"); |
| 358 | const StringTable = @import("../StringTable.zig"); |
src/link/Elf/ZigObject.zig+40-4| ... | ... | @@ -20,6 +20,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{}, |
| 20 | 20 | num_dynrelocs: u32 = 0, |
| 21 | 21 | |
| 22 | 22 | output_symtab_size: Elf.SymtabSize = .{}, |
| 23 | output_ar_state: Archive.ArState = .{}, | |
| 23 | 24 | |
| 24 | 25 | dwarf: ?Dwarf = null, |
| 25 | 26 | |
| ... | ... | @@ -502,10 +503,10 @@ fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void { |
| 502 | 503 | // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan); |
| 503 | 504 | } |
| 504 | 505 | |
| 505 | pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void { | |
| 506 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { | |
| 506 | 507 | const gpa = elf_file.base.allocator; |
| 507 | 508 | |
| 508 | try elf_file.ar_symtab.ensureUnusedCapacity(gpa, self.globals().len); | |
| 509 | try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len); | |
| 509 | 510 | |
| 510 | 511 | for (self.globals()) |global_index| { |
| 511 | 512 | const global = elf_file.symbol(global_index); |
| ... | ... | @@ -513,11 +514,45 @@ pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void { |
| 513 | 514 | assert(file_ptr.index() == self.index); |
| 514 | 515 | if (global.type(elf_file) == elf.SHN_UNDEF) continue; |
| 515 | 516 | |
| 516 | const off = try elf_file.ar_strtab.insert(gpa, global.name(elf_file)); | |
| 517 | elf_file.ar_symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index }); | |
| 517 | const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file)); | |
| 518 | ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index }); | |
| 518 | 519 | } |
| 519 | 520 | } |
| 520 | 521 | |
| 522 | pub fn updateArStrtab( | |
| 523 | self: *ZigObject, | |
| 524 | allocator: Allocator, | |
| 525 | ar_strtab: *Archive.ArStrtab, | |
| 526 | ) error{OutOfMemory}!void { | |
| 527 | const name = try std.fmt.allocPrint(allocator, "{s}.o", .{std.fs.path.stem(self.path)}); | |
| 528 | defer allocator.free(name); | |
| 529 | const name_off = try ar_strtab.insert(allocator, name); | |
| 530 | self.output_ar_state.name_off = name_off; | |
| 531 | } | |
| 532 | ||
| 533 | pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void { | |
| 534 | var end_pos: u64 = elf_file.shdr_table_offset.?; | |
| 535 | for (elf_file.shdrs.items) |shdr| { | |
| 536 | end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size); | |
| 537 | } | |
| 538 | self.output_ar_state.size = end_pos; | |
| 539 | } | |
| 540 | ||
| 541 | pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void { | |
| 542 | const gpa = elf_file.base.allocator; | |
| 543 | const contents = try gpa.alloc(u8, self.output_ar_state.size); | |
| 544 | defer gpa.free(contents); | |
| 545 | const amt = try elf_file.base.file.?.preadAll(contents, 0); | |
| 546 | if (amt != self.output_ar_state.size) return error.InputOutput; | |
| 547 | const hdr = Archive.setArHdr(.{ | |
| 548 | .kind = .object, | |
| 549 | .name_off = self.output_ar_state.name_off, | |
| 550 | .size = @intCast(self.output_ar_state.size), | |
| 551 | }); | |
| 552 | try writer.writeAll(mem.asBytes(&hdr)); | |
| 553 | try writer.writeAll(contents); | |
| 554 | } | |
| 555 | ||
| 521 | 556 | pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void { |
| 522 | 557 | _ = self; |
| 523 | 558 | |
| ... | ... | @@ -1533,6 +1568,7 @@ const std = @import("std"); |
| 1533 | 1568 | |
| 1534 | 1569 | const Air = @import("../../Air.zig"); |
| 1535 | 1570 | const Allocator = std.mem.Allocator; |
| 1571 | const Archive = @import("Archive.zig"); | |
| 1536 | 1572 | const Atom = @import("Atom.zig"); |
| 1537 | 1573 | const Dwarf = @import("../Dwarf.zig"); |
| 1538 | 1574 | const Elf = @import("../Elf.zig"); |
src/link/Elf/file.zig+3-2| ... | ... | @@ -196,9 +196,9 @@ pub const File = union(enum) { |
| 196 | 196 | } |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | pub fn updateArSymtab(file: File, elf_file: *Elf) !void { | |
| 199 | pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { | |
| 200 | 200 | return switch (file) { |
| 201 | .zig_object => |x| x.updateArSymtab(elf_file), | |
| 201 | .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file), | |
| 202 | 202 | .object => @panic("TODO"), |
| 203 | 203 | inline else => unreachable, |
| 204 | 204 | }; |
| ... | ... | @@ -219,6 +219,7 @@ const std = @import("std"); |
| 219 | 219 | const elf = std.elf; |
| 220 | 220 | |
| 221 | 221 | const Allocator = std.mem.Allocator; |
| 222 | const Archive = @import("Archive.zig"); | |
| 222 | 223 | const Atom = @import("Atom.zig"); |
| 223 | 224 | const Cie = @import("eh_frame.zig").Cie; |
| 224 | 225 | const Elf = @import("../Elf.zig"); |