| ... | @@ -24,6 +24,7 @@ base: link.File, | ... | @@ -24,6 +24,7 @@ base: link.File, |
| 24 | options: link.File.OpenOptions, | 24 | options: link.File.OpenOptions, |
| 25 | mf: MappedFile, | 25 | mf: MappedFile, |
| 26 | ni: Node.Known, | 26 | ni: Node.Known, |
| | 27 | archive: ?Archive, |
| 27 | nodes: std.MultiArrayList(Node), | 28 | nodes: std.MultiArrayList(Node), |
| 28 | /// Does not contain an item for `SHN_UNDEF`. | 29 | /// Does not contain an item for `SHN_UNDEF`. |
| 29 | shdrs: std.ArrayList(Section), | 30 | shdrs: std.ArrayList(Section), |
| ... | @@ -200,19 +201,39 @@ input_prog_node: std.Progress.Node, | ... | @@ -200,19 +201,39 @@ input_prog_node: std.Progress.Node, |
| 200 | const Error = link.Error || error{MappedFileIo}; | 201 | const Error = link.Error || error{MappedFileIo}; |
| 201 | | 202 | |
| 202 | const Node = union(enum) { | 203 | const Node = union(enum) { |
| | 204 | /// Only used when emitting a static library. |
| | 205 | /// |
| | 206 | /// Contains a header node which is an `.archive_header`. |
| | 207 | /// |
| | 208 | /// Contains the following footer nodes: |
| | 209 | /// * One `.archive_input_member` for each external input in the archive |
| | 210 | /// * One `.archive_elf_member_header` containing the `ar_hdr` for the ZCU |
| | 211 | /// * One `.elf` containing the ZCU's actual ELF object |
| | 212 | /// |
| | 213 | /// Padding between the headers and footers is absorbed into the "//" member (whose actual |
| | 214 | /// content is in the `.archive_header` node). |
| 203 | archive, | 215 | archive, |
| 204 | /// This includes the archive magic and long file member. | 216 | /// Only used when emitting a static library. |
| | 217 | /// |
| | 218 | /// Contains the archive magic (`ARMAG`), as well as the `ar_hdr` and content for the long file |
| | 219 | /// name string table member ("//"). |
| 205 | archive_header, | 220 | archive_header, |
| 206 | /// This is a footer of the `.elf` node, and contains the next archive entry's file header. | 221 | /// Only used when emitting a static library. |
| 207 | archive_elf_footer, | 222 | /// |
| | 223 | /// Contains the `ar_hdr` and content for one non-ZCU archive member (external link input). Also |
| | 224 | /// includes the single byte '\n' padding at the end of this archive member, if necessary. |
| | 225 | archive_input_member: InputIndex, |
| | 226 | /// Only used when emitting a static library. |
| | 227 | /// |
| | 228 | /// Contains the `ar_hdr` for the `.elf` node. |
| | 229 | archive_elf_member_header, |
| | 230 | |
| 208 | elf, | 231 | elf, |
| 209 | ehdr, | 232 | ehdr, |
| 210 | shdr, | 233 | shdr, |
| 211 | segment: u32, | 234 | segment: u32, |
| 212 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. | 235 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. |
| 213 | section: Section.Index, | 236 | section: Section.Index, |
| 214 | /// Only valid for static libraries, represents one non-zcu archive member. | | |
| 215 | input_member: InputIndex, | | |
| 216 | /// May contain relocations. | 237 | /// May contain relocations. |
| 217 | input_section: InputSection.Index, | 238 | input_section: InputSection.Index, |
| 218 | /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for | 239 | /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for |
| ... | @@ -404,6 +425,15 @@ const InputSection = struct { | ... | @@ -404,6 +425,15 @@ const InputSection = struct { |
| 404 | }; | 425 | }; |
| 405 | }; | 426 | }; |
| 406 | | 427 | |
| | 428 | const Archive = struct { |
| | 429 | ni: MappedFile.Node.Index, |
| | 430 | header_ni: MappedFile.Node.Index, |
| | 431 | elf_member_header_ni: MappedFile.Node.Index, |
| | 432 | |
| | 433 | elf_member_too_big: bool, |
| | 434 | strtab_member_too_big: bool, |
| | 435 | }; |
| | 436 | |
| 407 | const Section = struct { | 437 | const Section = struct { |
| 408 | /// The node corresponding to this section. | 438 | /// The node corresponding to this section. |
| 409 | ni: MappedFile.Node.Index, | 439 | ni: MappedFile.Node.Index, |
| ... | @@ -2954,13 +2984,13 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { | ... | @@ -2954,13 +2984,13 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| 2954 | const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { | 2984 | const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { |
| 2955 | .archive, | 2985 | .archive, |
| 2956 | .archive_header, | 2986 | .archive_header, |
| 2957 | .archive_elf_footer, | 2987 | .archive_input_member, |
| | 2988 | .archive_elf_member_header, |
| 2958 | .elf, | 2989 | .elf, |
| 2959 | .ehdr, | 2990 | .ehdr, |
| 2960 | .shdr, | 2991 | .shdr, |
| 2961 | .segment, | 2992 | .segment, |
| 2962 | .section, | 2993 | .section, |
| 2963 | .input_member, | | |
| 2964 | .input_section, | 2994 | .input_section, |
| 2965 | .copied_global, | 2995 | .copied_global, |
| 2966 | => unreachable, | 2996 | => unreachable, |
| ... | @@ -3364,6 +3394,7 @@ fn create( | ... | @@ -3364,6 +3394,7 @@ fn create( |
| 3364 | .data_rel_ro = undefined, | 3394 | .data_rel_ro = undefined, |
| 3365 | .tls = .none, | 3395 | .tls = .none, |
| 3366 | }, | 3396 | }, |
| | 3397 | .archive = null, |
| 3367 | .nodes = .empty, | 3398 | .nodes = .empty, |
| 3368 | .shdrs = .empty, | 3399 | .shdrs = .empty, |
| 3369 | .phdrs = .empty, | 3400 | .phdrs = .empty, |
| ... | @@ -3609,7 +3640,7 @@ fn initHeaders( | ... | @@ -3609,7 +3640,7 @@ fn initHeaders( |
| 3609 | }; | 3640 | }; |
| 3610 | }; | 3641 | }; |
| 3611 | | 3642 | |
| 3612 | const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_footer | 3643 | const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header |
| 3613 | 3 + // `.elf`, `.ehdr`, and `.shdr` nodes | 3644 | 3 + // `.elf`, `.ehdr`, and `.shdr` nodes |
| 3614 | (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node | 3645 | (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node |
| 3615 | (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node | 3646 | (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node |
| ... | @@ -3626,11 +3657,14 @@ fn initHeaders( | ... | @@ -3626,11 +3657,14 @@ fn initHeaders( |
| 3626 | const archive_ni: MappedFile.Node.Index = .root; | 3657 | const archive_ni: MappedFile.Node.Index = .root; |
| 3627 | | 3658 | |
| 3628 | const archive_header_ni = try archive_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ | 3659 | const archive_header_ni = try archive_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ |
| 3629 | .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2, | 3660 | // We intentionally do not set `.alignment = .@"2"` here, because the string table data |
| 3630 | .alignment = .@"2", | 3661 | // in this node does not need to have an aligned length. (This node's offset is aligned |
| 3631 | .next_moved = true, | 3662 | // regardless by virtue of it being a header.) |
| 3632 | .bubbles_moved = false, | 3663 | .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), |
| | 3664 | // The archive header uses 'next_moved' events to resize the "//" member, so that it |
| | 3665 | // absorbs all padding between `archive_header_ni` and the actual object file members. |
| 3633 | .enable_next_moved = true, | 3666 | .enable_next_moved = true, |
| | 3667 | .next_moved = true, |
| 3634 | }); | 3668 | }); |
| 3635 | elf.nodes.appendAssumeCapacity(.archive_header); | 3669 | elf.nodes.appendAssumeCapacity(.archive_header); |
| 3636 | const archive_header_slice = archive_header_ni.slice(&elf.mf); | 3670 | const archive_header_slice = archive_header_ni.slice(&elf.mf); |
| ... | @@ -3642,23 +3676,47 @@ fn initHeaders( | ... | @@ -3642,23 +3676,47 @@ fn initHeaders( |
| 3642 | .ar_uid = @splat(' '), | 3676 | .ar_uid = @splat(' '), |
| 3643 | .ar_gid = @splat(' '), | 3677 | .ar_gid = @splat(' '), |
| 3644 | .ar_mode = @splat(' '), | 3678 | .ar_mode = @splat(' '), |
| 3645 | .ar_size = @splat(' '), | 3679 | .ar_size = undefined, // populated by `flushNextMoved` for `archive_header_ni` |
| 3646 | .ar_fmag = std.elf.ARFMAG.*, | 3680 | .ar_fmag = std.elf.ARFMAG.*, |
| 3647 | }; | 3681 | }; |
| 3648 | | 3682 | |
| 3649 | elf.ni.elf = try archive_ni.addFloatingChild(&elf.mf, gpa, .{ | 3683 | elf.ni.elf = try archive_ni.addOnlyFooterChild(&elf.mf, gpa, .{ |
| 3650 | .alignment = node_block_align.max(.@"2"), | 3684 | .alignment = node_block_align.max(.@"2"), |
| 3651 | .next_moved = true, | | |
| 3652 | .bubbles_moved = false, | 3685 | .bubbles_moved = false, |
| 3653 | .enable_next_moved = true, | 3686 | .resized = true, // ensure that this node's `ar_hdr.ar_size` is updated at least once |
| 3654 | }); | 3687 | }); |
| 3655 | elf.nodes.appendAssumeCapacity(.elf); | 3688 | elf.nodes.appendAssumeCapacity(.elf); |
| 3656 | | 3689 | |
| 3657 | _ = try elf.ni.elf.addOnlyFooterChild(&elf.mf, gpa, .{ | 3690 | const elf_ar_hdr_ni = try archive_ni.addFooterChildBefore(&elf.mf, gpa, .wrap(elf.ni.elf), .{ |
| 3658 | .alignment = .@"2", | 3691 | .alignment = .@"2", |
| 3659 | .size = @sizeOf(std.elf.ar_hdr), | 3692 | .size = @sizeOf(std.elf.ar_hdr), |
| 3660 | }); | 3693 | }); |
| 3661 | elf.nodes.appendAssumeCapacity(.archive_elf_footer); | 3694 | elf.nodes.appendAssumeCapacity(.archive_elf_member_header); |
| | 3695 | |
| | 3696 | // Must be populated before we call `populateArchiveMemberName` below. |
| | 3697 | elf.archive = .{ |
| | 3698 | .ni = archive_ni, |
| | 3699 | .header_ni = archive_header_ni, |
| | 3700 | .elf_member_header_ni = elf_ar_hdr_ni, |
| | 3701 | |
| | 3702 | .elf_member_too_big = false, |
| | 3703 | .strtab_member_too_big = false, |
| | 3704 | }; |
| | 3705 | |
| | 3706 | const elf_ar_hdr: *std.elf.ar_hdr = @ptrCast(elf_ar_hdr_ni.slice(&elf.mf)); |
| | 3707 | elf_ar_hdr.* = .{ |
| | 3708 | .ar_name = undefined, // populated below |
| | 3709 | .ar_date = "0 ".*, |
| | 3710 | .ar_uid = "0 ".*, |
| | 3711 | .ar_gid = "0 ".*, |
| | 3712 | .ar_mode = "644 ".*, |
| | 3713 | .ar_size = undefined, // populated by `flushResized` for the `.elf` node |
| | 3714 | .ar_fmag = std.elf.ARFMAG.*, |
| | 3715 | }; |
| | 3716 | const zcu_member_name = try std.fmt.allocPrint(gpa, "{s}_zcu.o", .{comp.root_name}); |
| | 3717 | defer gpa.free(zcu_member_name); |
| | 3718 | // After this call returns, `elf_ar_hdr` is invalidated. |
| | 3719 | try elf.populateArchiveMemberName(elf_ar_hdr, zcu_member_name); |
| 3662 | } else { | 3720 | } else { |
| 3663 | elf.ni.elf = .root; | 3721 | elf.ni.elf = .root; |
| 3664 | elf.nodes.appendAssumeCapacity(.elf); | 3722 | elf.nodes.appendAssumeCapacity(.elf); |
| ... | @@ -4613,12 +4671,12 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { | ... | @@ -4613,12 +4671,12 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 4613 | return switch (elf.getNode(ni)) { | 4671 | return switch (elf.getNode(ni)) { |
| 4614 | .archive, | 4672 | .archive, |
| 4615 | .archive_header, | 4673 | .archive_header, |
| 4616 | .archive_elf_footer, | 4674 | .archive_input_member, |
| | 4675 | .archive_elf_member_header, |
| 4617 | .elf, | 4676 | .elf, |
| 4618 | .ehdr, | 4677 | .ehdr, |
| 4619 | .shdr, | 4678 | .shdr, |
| 4620 | .segment, | 4679 | .segment, |
| 4621 | .input_member, | | |
| 4622 | => unreachable, | 4680 | => unreachable, |
| 4623 | .section => |shndx| shndx, | 4681 | .section => |shndx| shndx, |
| 4624 | .input_section, | 4682 | .input_section, |
| ... | @@ -4634,12 +4692,12 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | ... | @@ -4634,12 +4692,12 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4634 | return switch (elf.getNode(ni)) { | 4692 | return switch (elf.getNode(ni)) { |
| 4635 | .archive, | 4693 | .archive, |
| 4636 | .archive_header, | 4694 | .archive_header, |
| 4637 | .archive_elf_footer, | 4695 | .archive_input_member, |
| | 4696 | .archive_elf_member_header, |
| 4638 | .elf, | 4697 | .elf, |
| 4639 | .ehdr, | 4698 | .ehdr, |
| 4640 | .shdr, | 4699 | .shdr, |
| 4641 | .segment, | 4700 | .segment, |
| 4642 | .input_member, | | |
| 4643 | .copied_global, | 4701 | .copied_global, |
| 4644 | => unreachable, | 4702 | => unreachable, |
| 4645 | .section => |shndx| shndx.vaddr(elf), | 4703 | .section => |shndx| shndx.vaddr(elf), |
| ... | @@ -4653,14 +4711,18 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | ... | @@ -4653,14 +4711,18 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4653 | } | 4711 | } |
| 4654 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | 4712 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4655 | const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { | 4713 | const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { |
| 4656 | .archive, .archive_header, .archive_elf_footer => unreachable, | 4714 | .archive, |
| | 4715 | .archive_header, |
| | 4716 | .archive_input_member, |
| | 4717 | .archive_elf_member_header, |
| | 4718 | => unreachable, |
| 4657 | .elf => return 0, | 4719 | .elf => return 0, |
| 4658 | .ehdr, .shdr => unreachable, | 4720 | .ehdr, .shdr => unreachable, |
| 4659 | .segment => |phndx| switch (elf.phdrSlice()) { | 4721 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 4660 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), | 4722 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), |
| 4661 | }, | 4723 | }, |
| 4662 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), | 4724 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), |
| 4663 | .input_member, .input_section, .copied_global => unreachable, | 4725 | .input_section, .copied_global => unreachable, |
| 4664 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), | 4726 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 4665 | }; | 4727 | }; |
| 4666 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); | 4728 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| ... | @@ -4679,12 +4741,12 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { | ... | @@ -4679,12 +4741,12 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 4679 | const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { | 4741 | const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { |
| 4680 | .archive, | 4742 | .archive, |
| 4681 | .archive_header, | 4743 | .archive_header, |
| 4682 | .archive_elf_footer, | 4744 | .archive_input_member, |
| | 4745 | .archive_elf_member_header, |
| 4683 | .elf, | 4746 | .elf, |
| 4684 | .ehdr, | 4747 | .ehdr, |
| 4685 | .shdr, | 4748 | .shdr, |
| 4686 | .segment, | 4749 | .segment, |
| 4687 | .input_member, | | |
| 4688 | .copied_global, | 4750 | .copied_global, |
| 4689 | => unreachable, // cannot contain relocs | 4751 | => unreachable, // cannot contain relocs |
| 4690 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) | 4752 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) |
| ... | @@ -4745,7 +4807,12 @@ fn flushMovedNodeRelocs( | ... | @@ -4745,7 +4807,12 @@ fn flushMovedNodeRelocs( |
| 4745 | // changed, so update the `offset` field of the `ElfN.Rela` entry. | 4807 | // changed, so update the `offset` field of the `ElfN.Rela` entry. |
| 4746 | reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); | 4808 | reloc.relaSection(elf).relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); |
| 4747 | } | 4809 | } |
| 4748 | reloc.apply(elf); | 4810 | // This is not just the inverse of the above condition, because if `reloc` is relative |
| | 4811 | // to the base of this DSO, then `rela_index` is an `R_*_RELATIVE` relocation, but we |
| | 4812 | // still need to call `SymbolReloc.apply` to update that relocation's addend. |
| | 4813 | if (elf.ehdrType() != .REL) { |
| | 4814 | reloc.apply(elf); |
| | 4815 | } |
| 4749 | } | 4816 | } |
| 4750 | } | 4817 | } |
| 4751 | | 4818 | |
| ... | @@ -5035,16 +5102,6 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { | ... | @@ -5035,16 +5102,6 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { |
| 5035 | } | 5102 | } |
| 5036 | } | 5103 | } |
| 5037 | | 5104 | |
| 5038 | fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr { | | |
| 5039 | assert(elf.ni.elf != .root); | | |
| 5040 | const file_offset = ni.fileLocation(&elf.mf, false).offset; | | |
| 5041 | return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) { | | |
| 5042 | else => unreachable, | | |
| 5043 | .archive_header => file_offset + std.elf.ARMAG.len, | | |
| 5044 | .elf, .input_member => file_offset - @sizeOf(std.elf.ar_hdr), | | |
| 5045 | })..][0..@sizeOf(std.elf.ar_hdr)])); | | |
| 5046 | } | | |
| 5047 | | | |
| 5048 | const SymPtr = union(std.elf.CLASS) { | 5105 | const SymPtr = union(std.elf.CLASS) { |
| 5049 | NONE: noreturn, | 5106 | NONE: noreturn, |
| 5050 | @"32": *std.elf.Elf32.Sym, | 5107 | @"32": *std.elf.Elf32.Sym, |
| ... | @@ -5544,19 +5601,61 @@ fn loadObject( | ... | @@ -5544,19 +5601,61 @@ fn loadObject( |
| 5544 | .member = if (member) |m| try gpa.dupe(u8, m) else null, | 5601 | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| 5545 | .extra = undefined, | 5602 | .extra = undefined, |
| 5546 | }; | 5603 | }; |
| 5547 | if (elf.ni.elf != .root) { | 5604 | if (elf.archive) |*archive| { |
| 5548 | const archive_ni: MappedFile.Node.Index = .root; | 5605 | // We're creating a static library, so just add this input as an archive member. |
| | 5606 | assert(member == null); // don't try to put static library members into other static libraries |
| | 5607 | |
| | 5608 | const first_member_oni = archive.header_ni.next(&elf.mf); |
| | 5609 | |
| | 5610 | if (first_member_oni.unwrap()) |first_member_ni| switch (elf.getNode(first_member_ni)) { |
| | 5611 | .archive_input_member, .archive_elf_member_header => {}, |
| | 5612 | .elf => unreachable, // always preceded by `.archive_elf_member_header` |
| | 5613 | else => unreachable, // never a child of `.archive` |
| | 5614 | }; |
| | 5615 | |
| 5549 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 5616 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5550 | input.extra = .{ .node = try archive_ni.addFloatingChild(&elf.mf, gpa, .{ | 5617 | const new_member_ni = try archive.ni.addFooterChildBefore(&elf.mf, gpa, first_member_oni, .{ |
| 5551 | .size = Alignment.@"2".forward(fl.size + @sizeOf(std.elf.ar_hdr)), | 5618 | .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size), |
| 5552 | .alignment = .@"2", | 5619 | .alignment = .@"2", |
| 5553 | .next_moved = true, | 5620 | }); |
| 5554 | .bubbles_moved = false, | 5621 | elf.nodes.appendAssumeCapacity(.{ .archive_input_member = input_index }); |
| 5555 | .enable_next_moved = true, | 5622 | input.extra = .{ .node = new_member_ni }; |
| 5556 | }) }; | | |
| 5557 | elf.nodes.appendAssumeCapacity(.{ .input_member = input_index }); | | |
| 5558 | elf.input_prog_node.increaseEstimatedTotalItems(1); | 5623 | elf.input_prog_node.increaseEstimatedTotalItems(1); |
| 5559 | | 5624 | |
| | 5625 | // The contents of the input will be written to the file by an idle task (`flushInput`), but |
| | 5626 | // we do need to write the input's archive member header (`ar_hdr`) now, for two reasons: |
| | 5627 | // |
| | 5628 | // * If the input file has a long name, we need to add it to the archive member name string |
| | 5629 | // table, which must happen deterministically (i.e. not in an idle task). |
| | 5630 | // |
| | 5631 | // * `flushInput` needs to know the actual file size (before padding to the alignment). |
| | 5632 | const member_ar_hdr: *std.elf.ar_hdr = @ptrCast( |
| | 5633 | new_member_ni.slice(&elf.mf)[0..@sizeOf(std.elf.ar_hdr)], |
| | 5634 | ); |
| | 5635 | member_ar_hdr.* = .{ |
| | 5636 | .ar_name = undefined, // populated below |
| | 5637 | .ar_date = "0 ".*, |
| | 5638 | .ar_uid = "0 ".*, |
| | 5639 | .ar_gid = "0 ".*, |
| | 5640 | .ar_mode = "644 ".*, |
| | 5641 | .ar_size = undefined, // populated below |
| | 5642 | .ar_fmag = std.elf.ARFMAG.*, |
| | 5643 | }; |
| | 5644 | |
| | 5645 | if (std.mem.print(&member_ar_hdr.ar_size, "{d}", .{fl.size})) |size_str| { |
| | 5646 | @memset(member_ar_hdr.ar_size[size_str.len..], ' '); |
| | 5647 | } else |err| switch (err) { |
| | 5648 | error.NoSpaceLeft => return diags.failParse( |
| | 5649 | path, |
| | 5650 | "file size of {Bi} exceeds maximum size of archive member", |
| | 5651 | .{fl.size}, |
| | 5652 | ), |
| | 5653 | } |
| | 5654 | |
| | 5655 | const member_name = std.fs.path.basename(path.sub_path); |
| | 5656 | // After this call returns, `member_ar_hdr` is invalidated. |
| | 5657 | try elf.populateArchiveMemberName(member_ar_hdr, member_name); |
| | 5658 | |
| 5560 | // Since we are not emitting the archive symbol table (yet?) we do not need to parse | 5659 | // Since we are not emitting the archive symbol table (yet?) we do not need to parse |
| 5561 | // the symbols in this input. | 5660 | // the symbols in this input. |
| 5562 | return; | 5661 | return; |
| ... | @@ -5969,6 +6068,46 @@ fn loadObject( | ... | @@ -5969,6 +6068,46 @@ fn loadObject( |
| 5969 | }, | 6068 | }, |
| 5970 | } | 6069 | } |
| 5971 | } | 6070 | } |
| | 6071 | /// This function may resize the archive header, so therefore invalidates `member_ar_hdr`. |
| | 6072 | fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_name: []const u8) Error!void { |
| | 6073 | if (std.mem.print(&member_ar_hdr.ar_name, "{s}/", .{member_name})) |name_str| { |
| | 6074 | @memset(member_ar_hdr.ar_name[name_str.len..], ' '); |
| | 6075 | return; |
| | 6076 | } else |err| switch (err) { |
| | 6077 | error.NoSpaceLeft => {}, // handled below |
| | 6078 | } |
| | 6079 | |
| | 6080 | const gpa = elf.base.comp.gpa; |
| | 6081 | const archive_header_ni = elf.archive.?.header_ni; |
| | 6082 | |
| | 6083 | // The member's name is too big to put directly in the `ar_name` field, so it needs to go in the |
| | 6084 | // "long name" string table instead (in the special member named "//"). |
| | 6085 | |
| | 6086 | _, const old_archive_header_size = archive_header_ni.location(&elf.mf).resolve(&elf.mf); |
| | 6087 | |
| | 6088 | // We're going to add a new string at the end of the table. Update `member_ar_hdr` first, |
| | 6089 | // because resizing the string table will invalidate it. |
| | 6090 | const string_table_offset = old_archive_header_size - (std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr)); |
| | 6091 | if (std.mem.print(&member_ar_hdr.ar_name, "/{d}", .{string_table_offset})) |name_str| { |
| | 6092 | @memset(member_ar_hdr.ar_name[name_str.len..], ' '); |
| | 6093 | } else |inner_err| switch (inner_err) { |
| | 6094 | error.NoSpaceLeft => { |
| | 6095 | // The string table offset is itself too big to represent. This means the string table's |
| | 6096 | // *size* is definitely too big to represent (we only get 10 bytes for that whereas we |
| | 6097 | // get 16 here!), so as long as we still add the string, we're guaranteed to get a link |
| | 6098 | // error for that reason. Therefore, we can just ignore this error and carry on. |
| | 6099 | }, |
| | 6100 | } |
| | 6101 | |
| | 6102 | // We set the size of the archive header node exactly, because we want padding bytes to go into |
| | 6103 | // the root `.archive` node. That way, those bytes could still be used to grow the string table |
| | 6104 | // if necessary, but they could also be used for new archive members. |
| | 6105 | try archive_header_ni.resizeLeaf(&elf.mf, gpa, old_archive_header_size + member_name.len + 2); |
| | 6106 | |
| | 6107 | const dest_slice = archive_header_ni.slice(&elf.mf)[@intCast(old_archive_header_size)..]; |
| | 6108 | @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name); |
| | 6109 | @memcpy(dest_slice[dest_slice.len - 2 ..], "/\n"); // yes, the terminator is weird |
| | 6110 | } |
| 5972 | fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { | 6111 | fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { |
| 5973 | const comp = elf.base.comp; | 6112 | const comp = elf.base.comp; |
| 5974 | const gpa = comp.gpa; | 6113 | const gpa = comp.gpa; |
| ... | @@ -7136,12 +7275,12 @@ fn addGotRelocAssumeCapacity( | ... | @@ -7136,12 +7275,12 @@ fn addGotRelocAssumeCapacity( |
| 7136 | switch (elf.getNode(node)) { | 7275 | switch (elf.getNode(node)) { |
| 7137 | .archive, | 7276 | .archive, |
| 7138 | .archive_header, | 7277 | .archive_header, |
| 7139 | .archive_elf_footer, | 7278 | .archive_input_member, |
| | 7279 | .archive_elf_member_header, |
| 7140 | .elf, | 7280 | .elf, |
| 7141 | .ehdr, | 7281 | .ehdr, |
| 7142 | .shdr, | 7282 | .shdr, |
| 7143 | .segment, | 7283 | .segment, |
| 7144 | .input_member, | | |
| 7145 | .copied_global, | 7284 | .copied_global, |
| 7146 | => unreachable, // cannot contain relocs, | 7285 | => unreachable, // cannot contain relocs, |
| 7147 | .section, | 7286 | .section, |
| ... | @@ -7579,6 +7718,17 @@ fn flushInner( | ... | @@ -7579,6 +7718,17 @@ fn flushInner( |
| 7579 | diags.addError("failed to apply {d} relocations: misaligned value", .{elf.misaligned_reloc_count}); | 7718 | diags.addError("failed to apply {d} relocations: misaligned value", .{elf.misaligned_reloc_count}); |
| 7580 | } | 7719 | } |
| 7581 | | 7720 | |
| | 7721 | if (elf.archive) |*archive| { |
| | 7722 | if (archive.elf_member_too_big) diags.addError( |
| | 7723 | "file size of {Bi} exceeds maximum size of archive member", |
| | 7724 | .{elf.ni.elf.location(&elf.mf).resolve(&elf.mf)[1]}, |
| | 7725 | ); |
| | 7726 | if (archive.strtab_member_too_big) diags.addError( |
| | 7727 | "archive file name string table exceeds maximum size", |
| | 7728 | .{}, |
| | 7729 | ); |
| | 7730 | } |
| | 7731 | |
| 7582 | elf.flushDynamic(); | 7732 | elf.flushDynamic(); |
| 7583 | | 7733 | |
| 7584 | const entry_addr: u64 = entry: { | 7734 | const entry_addr: u64 = entry: { |
| ... | @@ -7610,6 +7760,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { | ... | @@ -7610,6 +7760,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7610 | const comp = elf.base.comp; | 7760 | const comp = elf.base.comp; |
| 7611 | const diags = &comp.link_diags; | 7761 | const diags = &comp.link_diags; |
| 7612 | | 7762 | |
| | 7763 | elf.mf.nodes_lock.lock(); |
| | 7764 | defer elf.mf.nodes_lock.unlock(); |
| | 7765 | |
| 7613 | assert(elf.pending_uavs.items.len == 0); | 7766 | assert(elf.pending_uavs.items.len == 0); |
| 7614 | for (&elf.lazy.values) |*lazy| { | 7767 | for (&elf.lazy.values) |*lazy| { |
| 7615 | assert(lazy.pending_index == lazy.map.count()); | 7768 | assert(lazy.pending_index == lazy.map.count()); |
| ... | @@ -7763,7 +7916,7 @@ fn idleProgNode( | ... | @@ -7763,7 +7916,7 @@ fn idleProgNode( |
| 7763 | return prog_node.start(name: switch (node) { | 7916 | return prog_node.start(name: switch (node) { |
| 7764 | else => |tag| @tagName(tag), | 7917 | else => |tag| @tagName(tag), |
| 7765 | .section => |shndx| shndx.name(elf).slice(elf), | 7918 | .section => |shndx| shndx.name(elf).slice(elf), |
| 7766 | .input_member => |ii| std.fmt.bufPrint(&name, "{f}{f}", .{ | 7919 | .archive_input_member => |ii| std.fmt.bufPrint(&name, "{f}{f}", .{ |
| 7767 | ii.path(elf).fmtEscapeString(), | 7920 | ii.path(elf).fmtEscapeString(), |
| 7768 | fmtMemberString(ii.member(elf)), | 7921 | fmtMemberString(ii.member(elf)), |
| 7769 | }) catch &name, | 7922 | }) catch &name, |
| ... | @@ -7890,7 +8043,6 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { | ... | @@ -7890,7 +8043,6 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { |
| 7890 | fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { | 8043 | fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { |
| 7891 | const comp = elf.base.comp; | 8044 | const comp = elf.base.comp; |
| 7892 | const io = comp.io; | 8045 | const io = comp.io; |
| 7893 | const gpa = comp.gpa; | | |
| 7894 | const diags = &comp.link_diags; | 8046 | const diags = &comp.link_diags; |
| 7895 | const path = ii.path(elf); | 8047 | const path = ii.path(elf); |
| 7896 | const file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| switch (err) { | 8048 | const file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| switch (err) { |
| ... | @@ -7898,23 +8050,40 @@ fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { | ... | @@ -7898,23 +8050,40 @@ fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { |
| 7898 | else => |e| return diags.fail("failed to open input file \"{f}\": {t}", .{ path.fmtEscapeString(), e }), | 8050 | else => |e| return diags.fail("failed to open input file \"{f}\": {t}", .{ path.fmtEscapeString(), e }), |
| 7899 | }; | 8051 | }; |
| 7900 | defer file.close(io); | 8052 | defer file.close(io); |
| | 8053 | |
| | 8054 | const slice = ii.node(elf).slice(&elf.mf); |
| | 8055 | |
| | 8056 | const member_ar_hdr: *const std.elf.ar_hdr = @ptrCast(slice[0..@sizeOf(std.elf.ar_hdr)]); |
| | 8057 | const input_size: u32 = member_ar_hdr.size() catch |err| switch (err) { |
| | 8058 | // We wrote the `ar_hdr` ourselves (in `loadObject`), so it is definitely valid. |
| | 8059 | error.Overflow, error.InvalidCharacter => unreachable, |
| | 8060 | }; |
| | 8061 | |
| | 8062 | switch (slice.len - @sizeOf(std.elf.ar_hdr) - input_size) { |
| | 8063 | 0 => {}, |
| | 8064 | 1 => { |
| | 8065 | // Alignment added one padding byte, which the format requires to have value '\n'. |
| | 8066 | slice[slice.len - 1] = '\n'; |
| | 8067 | }, |
| | 8068 | else => unreachable, // node size should agree with the value we wrote into `ar_hdr.ar_size` |
| | 8069 | } |
| | 8070 | |
| 7901 | var fr = file.reader(io, &.{}); | 8071 | var fr = file.reader(io, &.{}); |
| 7902 | var nw: MappedFile.Node.Writer = undefined; | 8072 | var w: Io.Writer = .fixed(slice[@sizeOf(std.elf.ar_hdr)..]); |
| 7903 | ii.node(elf).writer(&elf.mf, gpa, &nw); | 8073 | const n_bytes_read = w.sendFileAll(&fr, .limited(input_size)) catch |err| switch (err) { |
| 7904 | defer nw.deinit(); | | |
| 7905 | const size = nw.interface.buffer.len - @sizeOf(std.elf.ar_hdr); | | |
| 7906 | const n_bytes = nw.interface.sendFileAll(&fr, .limited(size)) catch |err| switch (err) { | | |
| 7907 | error.ReadFailed => return diags.fail("failed to read input \"{f}{f}\": {t}", .{ | 8074 | error.ReadFailed => return diags.fail("failed to read input \"{f}{f}\": {t}", .{ |
| 7908 | path.fmtEscapeString(), | 8075 | path.fmtEscapeString(), |
| 7909 | fmtMemberString(ii.member(elf)), | 8076 | fmtMemberString(ii.member(elf)), |
| 7910 | fr.err orelse (fr.seek_err orelse fr.size_err.?), | 8077 | fr.err orelse (fr.seek_err orelse fr.size_err.?), |
| 7911 | }), | 8078 | }), |
| 7912 | error.WriteFailed => return nw.err.?, | 8079 | error.WriteFailed => unreachable, // `.limited(input_size)` prevents us writing too many bytes |
| 7913 | }; | 8080 | }; |
| 7914 | if (n_bytes + 1 < size) return diags.fail("failed to read input \"{f}{f}\": unexpected eof", .{ | 8081 | if (n_bytes_read != input_size) { |
| 7915 | path.fmtEscapeString(), | 8082 | return diags.fail("failed to load input \"{f}{f}\": file truncated during compilation", .{ |
| 7916 | fmtMemberString(ii.member(elf)), | 8083 | path.fmtEscapeString(), |
| 7917 | }); | 8084 | fmtMemberString(ii.member(elf)), |
| | 8085 | }); |
| | 8086 | } |
| 7918 | } | 8087 | } |
| 7919 | | 8088 | |
| 7920 | fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { | 8089 | fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { |
| ... | @@ -7996,12 +8165,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -7996,12 +8165,18 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7996 | const trace = tracy.trace(@src()); | 8165 | const trace = tracy.trace(@src()); |
| 7997 | defer trace.end(); | 8166 | defer trace.end(); |
| 7998 | | 8167 | |
| 7999 | elf.mf.nodes_lock.lock(); | | |
| 8000 | defer elf.mf.nodes_lock.unlock(); | | |
| 8001 | | | |
| 8002 | switch (elf.getNode(ni)) { | 8168 | switch (elf.getNode(ni)) { |
| 8003 | .archive, .archive_header => unreachable, | 8169 | .archive => unreachable, |
| 8004 | .archive_elf_footer, .elf => {}, | 8170 | .archive_header => unreachable, |
| | 8171 | |
| | 8172 | .archive_input_member, |
| | 8173 | .archive_elf_member_header, |
| | 8174 | .elf, |
| | 8175 | => { |
| | 8176 | assert(elf.archive != null); |
| | 8177 | return; |
| | 8178 | }, |
| | 8179 | |
| 8005 | .ehdr, .shdr => elf.flushElfOffset(ni), | 8180 | .ehdr, .shdr => elf.flushElfOffset(ni), |
| 8006 | .segment => |phndx| { | 8181 | .segment => |phndx| { |
| 8007 | elf.flushElfOffset(ni); | 8182 | elf.flushElfOffset(ni); |
| ... | @@ -8079,7 +8254,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -8079,7 +8254,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8079 | elf.flushMovedPltSection(.plt_sec, old_addr, addr); | 8254 | elf.flushMovedPltSection(.plt_sec, old_addr, addr); |
| 8080 | } | 8255 | } |
| 8081 | }, | 8256 | }, |
| 8082 | .input_member => {}, | | |
| 8083 | .input_section => |isi| { | 8257 | .input_section => |isi| { |
| 8084 | const old_section_addr = isi.ptr(elf).vaddr; | 8258 | const old_section_addr = isi.ptr(elf).vaddr; |
| 8085 | const new_section_addr = elf.computeNodeVAddr(ni); | 8259 | const new_section_addr = elf.computeNodeVAddr(ni); |
| ... | @@ -8320,24 +8494,23 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -8320,24 +8494,23 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 8320 | const trace = tracy.trace(@src()); | 8494 | const trace = tracy.trace(@src()); |
| 8321 | defer trace.end(); | 8495 | defer trace.end(); |
| 8322 | | 8496 | |
| 8323 | elf.mf.nodes_lock.lock(); | | |
| 8324 | defer elf.mf.nodes_lock.unlock(); | | |
| 8325 | | | |
| 8326 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); | 8497 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 8327 | switch (elf.getNode(ni)) { | 8498 | switch (elf.getNode(ni)) { |
| 8328 | .archive => { | 8499 | .archive, .archive_header => {}, |
| 8329 | if (ni.last(&elf.mf).unwrap()) |last_ni| { | 8500 | .archive_input_member => unreachable, |
| 8330 | if (last_ni.prev(&elf.mf).unwrap()) |prev_ni| { | 8501 | .archive_elf_member_header => unreachable, |
| 8331 | if (prev_ni.hasNextMoved(&elf.mf)) return; | 8502 | .elf => if (elf.archive) |*archive| { |
| 8332 | } | 8503 | const member_ar_hdr: *std.elf.ar_hdr = @ptrCast( |
| 8333 | const offset, _ = last_ni.location(&elf.mf).resolve(&elf.mf); | 8504 | archive.elf_member_header_ni.slice(&elf.mf), |
| 8334 | _ = std.mem.print(&elf.arHdrPtr(last_ni).ar_size, "{d:<10}", .{ | 8505 | ); |
| 8335 | size - offset, | 8506 | if (std.mem.print(&member_ar_hdr.ar_size, "{d}", .{size})) |size_str| { |
| 8336 | }) catch @panic("archive member too large"); | 8507 | @memset(member_ar_hdr.ar_size[size_str.len..], ' '); |
| | 8508 | archive.elf_member_too_big = false; |
| | 8509 | } else |err| switch (err) { |
| | 8510 | error.NoSpaceLeft => archive.elf_member_too_big = true, |
| 8337 | } | 8511 | } |
| 8338 | }, | 8512 | }, |
| 8339 | .archive_header, .elf => {}, | 8513 | .ehdr => unreachable, |
| 8340 | .ehdr, .archive_elf_footer => unreachable, | | |
| 8341 | .shdr => {}, | 8514 | .shdr => {}, |
| 8342 | .segment => |phndx| switch (elf.phdrSlice()) { | 8515 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 8343 | inline else => |phdr| { | 8516 | inline else => |phdr| { |
| ... | @@ -8409,7 +8582,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -8409,7 +8582,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 8409 | } | 8582 | } |
| 8410 | }, | 8583 | }, |
| 8411 | }, | 8584 | }, |
| 8412 | .input_member, .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {}, | 8585 | .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 8413 | } | 8586 | } |
| 8414 | } | 8587 | } |
| 8415 | | 8588 | |
| ... | @@ -8417,12 +8590,11 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! | ... | @@ -8417,12 +8590,11 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! |
| 8417 | const trace = tracy.trace(@src()); | 8590 | const trace = tracy.trace(@src()); |
| 8418 | defer trace.end(); | 8591 | defer trace.end(); |
| 8419 | | 8592 | |
| 8420 | elf.mf.nodes_lock.lock(); | | |
| 8421 | defer elf.mf.nodes_lock.unlock(); | | |
| 8422 | | | |
| 8423 | switch (elf.getNode(ni)) { | 8593 | switch (elf.getNode(ni)) { |
| 8424 | .archive, | 8594 | .archive, |
| 8425 | .archive_elf_footer, | 8595 | .archive_input_member, |
| | 8596 | .archive_elf_member_header, |
| | 8597 | .elf, |
| 8426 | .ehdr, | 8598 | .ehdr, |
| 8427 | .shdr, | 8599 | .shdr, |
| 8428 | .segment, | 8600 | .segment, |
| ... | @@ -8434,54 +8606,32 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! | ... | @@ -8434,54 +8606,32 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! |
| 8434 | .lazy_code, | 8606 | .lazy_code, |
| 8435 | .lazy_const_data, | 8607 | .lazy_const_data, |
| 8436 | => unreachable, | 8608 | => unreachable, |
| 8437 | .archive_header, .elf, .input_member => |_, tag| { | 8609 | |
| 8438 | const member_offset, const update_size = member_offset: { | 8610 | .archive_header => { |
| 8439 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); | 8611 | const archive = &elf.archive.?; |
| 8440 | break :member_offset switch (tag) { | 8612 | |
| 8441 | else => unreachable, | 8613 | // Because we can't just throw padding bytes in the middle of an archive file, we need |
| 8442 | .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true }, | 8614 | // the member name string table (the "//" member) to absorb all the padding bytes |
| 8443 | .elf, .input_member => .{ offset, !ni.prev(&elf.mf).unwrap().?.hasNextMoved(&elf.mf) }, | 8615 | // between it (in the `.archive_header` node) and the first actual member. |
| 8444 | }; | 8616 | const next_member_ni = ni.next(&elf.mf).unwrap() orelse { |
| 8445 | }; | 8617 | // I guess there are no link inputs yet? But there will be eventually! |
| 8446 | const member_size = if (ni.next(&elf.mf).unwrap()) |next_ni| member_size: { | 8618 | return; |
| 8447 | const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); | | |
| 8448 | const next_member_size = if (next_ni.next(&elf.mf).unwrap()) |next_next_ni| next_member_size: { | | |
| 8449 | const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf); | | |
| 8450 | const next_member_end = next_next_offset - @sizeOf(std.elf.ar_hdr); | | |
| 8451 | break :next_member_size next_member_end - next_offset; | | |
| 8452 | } else next_member_size: { | | |
| 8453 | _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); | | |
| 8454 | const next_member_end = parent_size; | | |
| 8455 | break :next_member_size next_member_end - next_offset; | | |
| 8456 | }; | | |
| 8457 | const ar_hdr = elf.arHdrPtr(next_ni); | | |
| 8458 | var name_buf: [16]u8 = undefined; | | |
| 8459 | _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{ | | |
| 8460 | switch (elf.getNode(next_ni)) { | | |
| 8461 | else => unreachable, | | |
| 8462 | .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}), | | |
| 8463 | .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{ | | |
| 8464 | std.fs.path.basename(ii.path(elf).sub_path), | | |
| 8465 | }), | | |
| 8466 | } catch @panic("TODO: long archive member names"), | | |
| 8467 | }) catch @panic("TODO: long archive member names"); | | |
| 8468 | ar_hdr.ar_date = "0 ".*; | | |
| 8469 | ar_hdr.ar_uid = "0 ".*; | | |
| 8470 | ar_hdr.ar_gid = "0 ".*; | | |
| 8471 | ar_hdr.ar_mode = "644 ".*; | | |
| 8472 | _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch | | |
| 8473 | @panic("archive member too large"); | | |
| 8474 | ar_hdr.ar_fmag = std.elf.ARFMAG.*; | | |
| 8475 | const member_end = next_offset - @sizeOf(std.elf.ar_hdr); | | |
| 8476 | break :member_size member_end - member_offset; | | |
| 8477 | } else member_size: { | | |
| 8478 | _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); | | |
| 8479 | const member_end = parent_size; | | |
| 8480 | break :member_size member_end - member_offset; | | |
| 8481 | }; | 8619 | }; |
| 8482 | if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{ | 8620 | const next_member_offset: u64, _ = next_member_ni.location(&elf.mf).resolve(&elf.mf); |
| 8483 | member_size, | 8621 | const strtab_member_offset = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr); |
| 8484 | }) catch @panic("archive member too large"); | 8622 | assert(Alignment.@"2".check(next_member_offset)); |
| | 8623 | assert(Alignment.@"2".check(strtab_member_offset)); |
| | 8624 | const strtab_size = next_member_offset - strtab_member_offset; |
| | 8625 | |
| | 8626 | const member_ar_hdr: *std.elf.ar_hdr = @ptrCast( |
| | 8627 | archive.header_ni.slice(&elf.mf)[std.elf.ARMAG.len..][0..@sizeOf(std.elf.ar_hdr)], |
| | 8628 | ); |
| | 8629 | if (std.mem.print(&member_ar_hdr.ar_size, "{d}", .{strtab_size})) |size_str| { |
| | 8630 | @memset(member_ar_hdr.ar_size[size_str.len..], ' '); |
| | 8631 | archive.strtab_member_too_big = false; |
| | 8632 | } else |err| switch (err) { |
| | 8633 | error.NoSpaceLeft => archive.strtab_member_too_big = true, |
| | 8634 | } |
| 8485 | }, | 8635 | }, |
| 8486 | } | 8636 | } |
| 8487 | } | 8637 | } |