| ... | @@ -66,6 +66,8 @@ shndx: struct { | ... | @@ -66,6 +66,8 @@ shndx: struct { |
| 66 | debug_rnglists: Section.Index, | 66 | debug_rnglists: Section.Index, |
| 67 | debug_str: Section.Index, | 67 | debug_str: Section.Index, |
| 68 | debug_str_offsets: Section.Index, | 68 | debug_str_offsets: Section.Index, |
| | 69 | bss: Section.Index, |
| | 70 | tbss: Section.Index, |
| 69 | // These sections are created only as needed, and are initially `.UNDEF`. | 71 | // These sections are created only as needed, and are initially `.UNDEF`. |
| 70 | init_array: Section.Index, | 72 | init_array: Section.Index, |
| 71 | fini_array: Section.Index, | 73 | fini_array: Section.Index, |
| ... | @@ -135,6 +137,10 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa | ... | @@ -135,6 +137,10 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa |
| 135 | /// See the definition of `DsoGlobals`. | 137 | /// See the definition of `DsoGlobals`. |
| 136 | dso_globals: DsoGlobals, | 138 | dso_globals: DsoGlobals, |
| 137 | | 139 | |
| | 140 | // These are needed to find local symbols when a nodeless section moves. |
| | 141 | bss_inputs: std.ArrayList(Node.InputIndex), |
| | 142 | tbss_inputs: std.ArrayList(Node.InputIndex), |
| | 143 | |
| 138 | shstrtab: StringTable, | 144 | shstrtab: StringTable, |
| 139 | strtab: StringTable, | 145 | strtab: StringTable, |
| 140 | dynstr: StringTable, | 146 | dynstr: StringTable, |
| ... | @@ -491,7 +497,8 @@ const Archive = struct { | ... | @@ -491,7 +497,8 @@ const Archive = struct { |
| 491 | }; | 497 | }; |
| 492 | | 498 | |
| 493 | const Section = struct { | 499 | const Section = struct { |
| 494 | /// The node corresponding to this section. | 500 | /// File-backed node corresponding to this section. |
| | 501 | /// This is `.none` for `SHT_NOBITS` sections. |
| 495 | ni: MappedFile.Node.Index.Optional, | 502 | ni: MappedFile.Node.Index.Optional, |
| 496 | /// A symbol which is exactly at the start of this section. | 503 | /// A symbol which is exactly at the start of this section. |
| 497 | /// | 504 | /// |
| ... | @@ -655,14 +662,30 @@ const Section = struct { | ... | @@ -655,14 +662,30 @@ const Section = struct { |
| 655 | elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits())); | 662 | elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits())); |
| 656 | }, | 663 | }, |
| 657 | } | 664 | } |
| 658 | const ni = shndx.node(elf); | 665 | |
| 659 | if (min_align.compare(.gt, ni.alignment(&elf.mf))) { | 666 | if (shndx.get(elf).ni.unwrap()) |ni| { |
| 660 | try ni.realign(elf.base.comp.gpa, &elf.mf, min_align); | 667 | if (min_align.compare(.gt, ni.alignment(&elf.mf))) { |
| 661 | } | 668 | try ni.realign(elf.base.comp.gpa, &elf.mf, min_align); |
| 662 | switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { | 669 | } |
| 663 | .elf => {}, | 670 | switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { |
| 664 | .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align), | 671 | .elf => {}, |
| 665 | else => unreachable, | 672 | .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align), |
| | 673 | else => unreachable, |
| | 674 | } |
| | 675 | } else { |
| | 676 | // For sections without nodes (NOBITS), propagate alignment to the parent. |
| | 677 | assert(switch (elf.shdrPtr(shndx)) { |
| | 678 | inline else => |shdr| elf.targetLoad(&shdr.type) == .NOBITS, |
| | 679 | }); |
| | 680 | |
| | 681 | if (elf.ehdrType() == .REL) return; |
| | 682 | |
| | 683 | const segment_ni = if (shndx.flags(elf).TLS) |
| | 684 | elf.ni.tls.unwrap().? |
| | 685 | else |
| | 686 | elf.ni.data; |
| | 687 | |
| | 688 | try elf.ensureSegmentAligned(elf.getNode(segment_ni).segment, min_align); |
| 666 | } | 689 | } |
| 667 | } | 690 | } |
| 668 | | 691 | |
| ... | @@ -4718,6 +4741,8 @@ fn create( | ... | @@ -4718,6 +4741,8 @@ fn create( |
| 4718 | .init_array = .UNDEF, | 4741 | .init_array = .UNDEF, |
| 4719 | .fini_array = .UNDEF, | 4742 | .fini_array = .UNDEF, |
| 4720 | .preinit_array = .UNDEF, | 4743 | .preinit_array = .UNDEF, |
| | 4744 | .bss = .UNDEF, |
| | 4745 | .tbss = .UNDEF, |
| 4721 | }, | 4746 | }, |
| 4722 | .dynamic = .{ | 4747 | .dynamic = .{ |
| 4723 | .flags = 0, | 4748 | .flags = 0, |
| ... | @@ -4745,6 +4770,8 @@ fn create( | ... | @@ -4745,6 +4770,8 @@ fn create( |
| 4745 | .symbols = .empty, | 4770 | .symbols = .empty, |
| 4746 | .default_sym_vers = .empty, | 4771 | .default_sym_vers = .empty, |
| 4747 | }, | 4772 | }, |
| | 4773 | .bss_inputs = .empty, |
| | 4774 | .tbss_inputs = .empty, |
| 4748 | .shstrtab = .{ .map = .empty }, | 4775 | .shstrtab = .{ .map = .empty }, |
| 4749 | .strtab = .{ .map = .empty }, | 4776 | .strtab = .{ .map = .empty }, |
| 4750 | .dynstr = .{ .map = .empty }, | 4777 | .dynstr = .{ .map = .empty }, |
| ... | @@ -4827,6 +4854,8 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -4827,6 +4854,8 @@ pub fn deinit(elf: *Elf) void { |
| 4827 | elf.dso_globals.string_bytes.deinit(gpa); | 4854 | elf.dso_globals.string_bytes.deinit(gpa); |
| 4828 | elf.dso_globals.symbols.deinit(gpa); | 4855 | elf.dso_globals.symbols.deinit(gpa); |
| 4829 | elf.dso_globals.default_sym_vers.deinit(gpa); | 4856 | elf.dso_globals.default_sym_vers.deinit(gpa); |
| | 4857 | elf.bss_inputs.deinit(gpa); |
| | 4858 | elf.tbss_inputs.deinit(gpa); |
| 4830 | elf.shstrtab.map.deinit(gpa); | 4859 | elf.shstrtab.map.deinit(gpa); |
| 4831 | elf.strtab.map.deinit(gpa); | 4860 | elf.strtab.map.deinit(gpa); |
| 4832 | elf.dynstr.map.deinit(gpa); | 4861 | elf.dynstr.map.deinit(gpa); |
| ... | @@ -4912,7 +4941,9 @@ fn initHeaders( | ... | @@ -4912,7 +4941,9 @@ fn initHeaders( |
| 4912 | shnum += 1; // .rodata | 4941 | shnum += 1; // .rodata |
| 4913 | shnum += 1; // .text | 4942 | shnum += 1; // .text |
| 4914 | shnum += 1; // .data | 4943 | shnum += 1; // .data |
| | 4944 | shnum += 1; // .bss |
| 4915 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata | 4945 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata |
| | 4946 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tbss |
| 4916 | shnum += 1; // .data.rel.ro | 4947 | shnum += 1; // .data.rel.ro |
| 4917 | if (have_dynamic) { | 4948 | if (have_dynamic) { |
| 4918 | shnum += 1; // .dynamic | 4949 | shnum += 1; // .dynamic |
| ... | @@ -5029,9 +5060,13 @@ fn initHeaders( | ... | @@ -5029,9 +5060,13 @@ fn initHeaders( |
| 5029 | }; | 5060 | }; |
| 5030 | }; | 5061 | }; |
| 5031 | | 5062 | |
| | 5063 | // NOBITS sections don't contribute nodes. |
| | 5064 | const nobits_shnum: u32 = |
| | 5065 | @as(u32, 1) + @intFromBool(comp.config.any_non_single_threaded); |
| | 5066 | |
| 5032 | const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header | 5067 | const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header |
| 5033 | 3 + // `.elf`, `.ehdr`, and `.shdr` nodes | 5068 | 3 + // `.elf`, `.ehdr`, and `.shdr` nodes |
| 5034 | (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node | 5069 | (shnum - 1 - nobits_shnum) + // -1 because the SHN_UNDEF shdr does not have a `.section` node |
| 5035 | (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node | 5070 | (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node |
| 5036 | @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer | 5071 | @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer |
| 5037 | | 5072 | |
| ... | @@ -5521,6 +5556,13 @@ fn initHeaders( | ... | @@ -5521,6 +5556,13 @@ fn initHeaders( |
| 5521 | .flags = .{ .WRITE = true, .ALLOC = true }, | 5556 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 5522 | .node_align = node_block_align, | 5557 | .node_align = node_block_align, |
| 5523 | })); | 5558 | })); |
| | 5559 | |
| | 5560 | elf.shndx.bss = try elf.addSection(elf.ni.data, .{ |
| | 5561 | .name = ".bss", |
| | 5562 | .type = .NOBITS, |
| | 5563 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| | 5564 | }); |
| | 5565 | |
| 5524 | if (@"type" != .REL) { | 5566 | if (@"type" != .REL) { |
| 5525 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ | 5567 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ |
| 5526 | .name = ".got", | 5568 | .name = ".got", |
| ... | @@ -6119,11 +6161,19 @@ fn initHeaders( | ... | @@ -6119,11 +6161,19 @@ fn initHeaders( |
| 6119 | .manual_size = true, | 6161 | .manual_size = true, |
| 6120 | }); | 6162 | }); |
| 6121 | } | 6163 | } |
| 6122 | if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{ | 6164 | if (elf.ni.tls.unwrap()) |tls_segment_ni| { |
| 6123 | .name = ".tdata", | 6165 | elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{ |
| 6124 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, | 6166 | .name = ".tdata", |
| 6125 | .node_align = node_block_align, | 6167 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 6126 | }); | 6168 | .node_align = node_block_align, |
| | 6169 | }); |
| | 6170 | |
| | 6171 | elf.shndx.tbss = try elf.addSection(tls_segment_ni, .{ |
| | 6172 | .name = ".tbss", |
| | 6173 | .type = .NOBITS, |
| | 6174 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| | 6175 | }); |
| | 6176 | } |
| 6127 | switch (comp.config.debug_format) { | 6177 | switch (comp.config.debug_format) { |
| 6128 | .strip => {}, | 6178 | .strip => {}, |
| 6129 | .dwarf => { | 6179 | .dwarf => { |
| ... | @@ -6330,6 +6380,23 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | ... | @@ -6330,6 +6380,23 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 6330 | => elf.computeNodeVAddr(ni), | 6380 | => elf.computeNodeVAddr(ni), |
| 6331 | }; | 6381 | }; |
| 6332 | } | 6382 | } |
| | 6383 | |
| | 6384 | fn tbssSegmentOffset(elf: *Elf) u64 { |
| | 6385 | const tbss_addr = elf.shndx.tbss.vaddr(elf); |
| | 6386 | |
| | 6387 | // Hasn't been laid out yet. |
| | 6388 | if (tbss_addr == 0) return 0; |
| | 6389 | |
| | 6390 | const tls_ni = elf.ni.tls.unwrap().?; |
| | 6391 | const tls_phndx = elf.getNode(tls_ni).segment; |
| | 6392 | |
| | 6393 | const tls_vaddr = switch (elf.phdrSlice()) { |
| | 6394 | inline else => |phdr| elf.targetLoad(&phdr[tls_phndx].vaddr), |
| | 6395 | }; |
| | 6396 | |
| | 6397 | return tbss_addr - tls_vaddr; |
| | 6398 | } |
| | 6399 | |
| 6333 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | 6400 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 6334 | const parent_ni = ni.parent(&elf.mf).unwrap().?; | 6401 | const parent_ni = ni.parent(&elf.mf).unwrap().?; |
| 6335 | const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) { | 6402 | const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) { |
| ... | @@ -6942,6 +7009,7 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -6942,6 +7009,7 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 6942 | name: []const u8, | 7009 | name: []const u8, |
| 6943 | flags: std.elf.SHF, | 7010 | flags: std.elf.SHF, |
| 6944 | entsize: std.elf.Xword, | 7011 | entsize: std.elf.Xword, |
| | 7012 | type: std.elf.SHT = .PROGBITS, |
| 6945 | }) (Error || error{ | 7013 | }) (Error || error{ |
| 6946 | UnsupportedSectionFlags, | 7014 | UnsupportedSectionFlags, |
| 6947 | TlsSectionUnavailable, | 7015 | TlsSectionUnavailable, |
| ... | @@ -6979,12 +7047,10 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -6979,12 +7047,10 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 6979 | if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data"; | 7047 | if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data"; |
| 6980 | if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata"; | 7048 | if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata"; |
| 6981 | if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table"; | 7049 | if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table"; |
| 6982 | // TODO: actually generate a bss section! | 7050 | if (std.mem.eql(u8, opts.name, ".bss")) break :name ".bss"; |
| 6983 | if (std.mem.eql(u8, opts.name, ".bss")) break :name ".data"; | 7051 | if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".bss"; |
| 6984 | if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".data"; | 7052 | if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tbss"; |
| 6985 | // TODO: actually generate a tbss section! | 7053 | if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tbss"; |
| 6986 | if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tdata"; | | |
| 6987 | if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tdata"; | | |
| 6988 | break :name opts.name; | 7054 | break :name opts.name; |
| 6989 | }, | 7055 | }, |
| 6990 | }; | 7056 | }; |
| ... | @@ -7005,7 +7071,11 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -7005,7 +7071,11 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 7005 | assert(gop.index == elf.shdrs.items.len); | 7071 | assert(gop.index == elf.shdrs.items.len); |
| 7006 | return elf.addSection(parent_node, .{ | 7072 | return elf.addSection(parent_node, .{ |
| 7007 | .name = name, | 7073 | .name = name, |
| 7008 | .type = .NULL, // because initial size is 0 | 7074 | .type = switch (opts.type) { |
| | 7075 | .PROGBITS => .NULL, // size is 0 |
| | 7076 | .NOBITS => .NOBITS, |
| | 7077 | else => unreachable, |
| | 7078 | }, |
| 7009 | .flags = flags: { | 7079 | .flags = flags: { |
| 7010 | // We need to decompress the section for linking. | 7080 | // We need to decompress the section for linking. |
| 7011 | var flags = opts.flags; | 7081 | var flags = opts.flags; |
| ... | @@ -7026,9 +7096,20 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -7026,9 +7096,20 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 7026 | return error.SectionFlagsConflict; | 7096 | return error.SectionFlagsConflict; |
| 7027 | } | 7097 | } |
| 7028 | | 7098 | |
| 7029 | switch (elf.targetLoad(&shdr.type)) { | 7099 | const existing_type = elf.targetLoad(&shdr.type); |
| 7030 | .NULL, .PROGBITS, .X86_64_UNWIND => {}, | 7100 | |
| 7031 | else => return error.SectionTypeConflict, | 7101 | switch (opts.type) { |
| | 7102 | .PROGBITS => switch (existing_type) { |
| | 7103 | .NULL, .PROGBITS, .X86_64_UNWIND => {}, |
| | 7104 | else => return error.SectionTypeConflict, |
| | 7105 | }, |
| | 7106 | |
| | 7107 | .NOBITS => switch (existing_type) { |
| | 7108 | .NOBITS => {}, |
| | 7109 | else => return error.SectionTypeConflict, |
| | 7110 | }, |
| | 7111 | |
| | 7112 | else => unreachable, |
| 7032 | } | 7113 | } |
| 7033 | | 7114 | |
| 7034 | // All okay, combine the section flags | 7115 | // All okay, combine the section flags |
| ... | @@ -7447,6 +7528,9 @@ fn loadObject( | ... | @@ -7447,6 +7528,9 @@ fn loadObject( |
| 7447 | .type = .FILE, | 7528 | .type = .FILE, |
| 7448 | .shndx = .ABS, | 7529 | .shndx = .ABS, |
| 7449 | }) }; | 7530 | }) }; |
| | 7531 | |
| | 7532 | var input_has_bss = false; |
| | 7533 | var input_has_tbss = false; |
| 7450 | const target_endian = elf.targetEndian(); | 7534 | const target_endian = elf.targetEndian(); |
| 7451 | switch (elf.identClass()) { | 7535 | switch (elf.identClass()) { |
| 7452 | .NONE, _ => unreachable, | 7536 | .NONE, _ => unreachable, |
| ... | @@ -7461,13 +7545,28 @@ fn loadObject( | ... | @@ -7461,13 +7545,28 @@ fn loadObject( |
| 7461 | return diags.failParse(path, "bad section header location", .{}); | 7545 | return diags.failParse(path, "bad section header location", .{}); |
| 7462 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 7546 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 7463 | return diags.failParse(path, "unsupported shentsize", .{}); | 7547 | return diags.failParse(path, "unsupported shentsize", .{}); |
| 7464 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, isi: ?InputSection.Index }, ehdr.shnum); | 7548 | |
| | 7549 | const sections = try gpa.alloc(struct { |
| | 7550 | shdr: ElfN.Shdr, |
| | 7551 | placement: ?union(enum) { |
| | 7552 | progbits: InputSection.Index, |
| | 7553 | bss: struct { |
| | 7554 | shndx: Section.Index, |
| | 7555 | offset: u64, |
| | 7556 | }, |
| | 7557 | tbss: struct { |
| | 7558 | shndx: Section.Index, |
| | 7559 | offset: u64, |
| | 7560 | }, |
| | 7561 | }, |
| | 7562 | }, ehdr.shnum); |
| | 7563 | |
| 7465 | defer gpa.free(sections); | 7564 | defer gpa.free(sections); |
| 7466 | try fr.seekTo(fl.offset + ehdr.shoff); | 7565 | try fr.seekTo(fl.offset + ehdr.shoff); |
| 7467 | for (sections) |*section| { | 7566 | for (sections) |*section| { |
| 7468 | section.* = .{ | 7567 | section.* = .{ |
| 7469 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), | 7568 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| 7470 | .isi = null, | 7569 | .placement = null, |
| 7471 | }; | 7570 | }; |
| 7472 | try r.discardAll(ehdr.shentsize); | 7571 | try r.discardAll(ehdr.shentsize); |
| 7473 | switch (section.shdr.type) { | 7572 | switch (section.shdr.type) { |
| ... | @@ -7494,16 +7593,22 @@ fn loadObject( | ... | @@ -7494,16 +7593,22 @@ fn loadObject( |
| 7494 | if (section.shdr.name >= shstrtab.len) continue; | 7593 | if (section.shdr.name >= shstrtab.len) continue; |
| 7495 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); | 7594 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 7496 | if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue; | 7595 | if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue; |
| | 7596 | const sect_type = section.shdr.type; |
| | 7597 | const is_bss = (std.mem.startsWith(u8, name, ".bss.") or |
| | 7598 | std.mem.eql(u8, name, ".bss")) and sect_type == .NOBITS; |
| | 7599 | const is_tbss = (std.mem.startsWith(u8, name, ".tbss.") or |
| | 7600 | std.mem.eql(u8, name, ".tbss")) and sect_type == .NOBITS; |
| 7497 | const opts: struct { | 7601 | const opts: struct { |
| 7498 | shndx: Section.Index, | 7602 | shndx: Section.Index, |
| 7499 | node_fixed: bool, | 7603 | node_fixed: bool, |
| 7500 | } = switch (section.shdr.type) { | 7604 | } = switch (sect_type) { |
| 7501 | else => continue, | 7605 | else => continue, |
| 7502 | .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: { | 7606 | .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: { |
| 7503 | const shndx = elf.mapInputSection(.{ | 7607 | const shndx = elf.mapInputSection(.{ |
| 7504 | .name = name, | 7608 | .name = name, |
| 7505 | .flags = section.shdr.flags.shf, | 7609 | .flags = section.shdr.flags.shf, |
| 7506 | .entsize = section.shdr.entsize, | 7610 | .entsize = section.shdr.entsize, |
| | 7611 | .type = if (is_bss or is_tbss) .NOBITS else .PROGBITS, |
| 7507 | }) catch |err| switch (err) { | 7612 | }) catch |err| switch (err) { |
| 7508 | else => |e| return e, | 7613 | else => |e| return e, |
| 7509 | error.StripSection => continue, | 7614 | error.StripSection => continue, |
| ... | @@ -7559,7 +7664,8 @@ fn loadObject( | ... | @@ -7559,7 +7664,8 @@ fn loadObject( |
| 7559 | shndx != .rodata and | 7664 | shndx != .rodata and |
| 7560 | shndx != .data and | 7665 | shndx != .data and |
| 7561 | shndx != .data_rel_ro and | 7666 | shndx != .data_rel_ro and |
| 7562 | shndx != elf.shndx.tdata, | 7667 | shndx != elf.shndx.tdata and |
| | 7668 | shndx != elf.shndx.tbss, |
| 7563 | }; | 7669 | }; |
| 7564 | }, | 7670 | }, |
| 7565 | inline .INIT_ARRAY, .FINI_ARRAY, .PREINIT_ARRAY => |@"type"| .{ | 7671 | inline .INIT_ARRAY, .FINI_ARRAY, .PREINIT_ARRAY => |@"type"| .{ |
| ... | @@ -7602,7 +7708,43 @@ fn loadObject( | ... | @@ -7602,7 +7708,43 @@ fn loadObject( |
| 7602 | const need_align: Alignment = .fromByteUnits( | 7708 | const need_align: Alignment = .fromByteUnits( |
| 7603 | std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))), | 7709 | std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))), |
| 7604 | ); | 7710 | ); |
| | 7711 | |
| 7605 | try opts.shndx.ensureAligned(elf, need_align); | 7712 | try opts.shndx.ensureAligned(elf, need_align); |
| | 7713 | |
| | 7714 | if (is_bss or is_tbss) { |
| | 7715 | const offset: u64 = offset: { |
| | 7716 | switch (elf.shdrPtr(opts.shndx)) { |
| | 7717 | inline else => |shdr| { |
| | 7718 | // Bump our BSS output section size. |
| | 7719 | const old_size: u64 = elf.targetLoad(&shdr.size); |
| | 7720 | const offset = need_align.forward(old_size); |
| | 7721 | const new_size = offset + section.shdr.size; |
| | 7722 | elf.targetStore(&shdr.size, @intCast(new_size)); |
| | 7723 | break :offset offset; |
| | 7724 | }, |
| | 7725 | } |
| | 7726 | }; |
| | 7727 | |
| | 7728 | if (is_bss) { |
| | 7729 | section.placement = .{ .bss = .{ |
| | 7730 | .shndx = opts.shndx, |
| | 7731 | .offset = offset, |
| | 7732 | } }; |
| | 7733 | input_has_bss = true; |
| | 7734 | continue; |
| | 7735 | } |
| | 7736 | |
| | 7737 | if (is_tbss) { |
| | 7738 | section.placement = .{ .tbss = .{ |
| | 7739 | .shndx = opts.shndx, |
| | 7740 | .offset = offset, |
| | 7741 | } }; |
| | 7742 | input_has_tbss = true; |
| | 7743 | } |
| | 7744 | |
| | 7745 | continue; |
| | 7746 | } |
| | 7747 | |
| 7606 | const add_node_opts: MappedFile.Node.AddOptions = .{ | 7748 | const add_node_opts: MappedFile.Node.AddOptions = .{ |
| 7607 | .size = need_align.forward(section.shdr.size), | 7749 | .size = need_align.forward(section.shdr.size), |
| 7608 | .alignment = need_align, | 7750 | .alignment = need_align, |
| ... | @@ -7622,7 +7764,7 @@ fn loadObject( | ... | @@ -7622,7 +7764,7 @@ fn loadObject( |
| 7622 | } else try opts.shndx.node(elf).addFloatingChild(gpa, &elf.mf, add_node_opts), | 7764 | } else try opts.shndx.node(elf).addFloatingChild(gpa, &elf.mf, add_node_opts), |
| 7623 | .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) }, | 7765 | .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) }, |
| 7624 | ); | 7766 | ); |
| 7625 | section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len)); | 7767 | section.placement = .{ .progbits = @fromBackingInt(@intCast(elf.input_sections.items.len)) }; |
| 7626 | elf.input_sections.addOneAssumeCapacity().* = .{ | 7768 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 7627 | .input = input_index, | 7769 | .input = input_index, |
| 7628 | .file_location = .{ | 7770 | .file_location = .{ |
| ... | @@ -7719,7 +7861,31 @@ fn loadObject( | ... | @@ -7719,7 +7861,31 @@ fn loadObject( |
| 7719 | }, | 7861 | }, |
| 7720 | }; | 7862 | }; |
| 7721 | | 7863 | |
| 7722 | const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf); | 7864 | const placement = |
| | 7865 | sections[input_sym.shndx].placement orelse continue; |
| | 7866 | |
| | 7867 | const symbol_oni: MappedFile.Node.Index.Optional, const output_shndx, const symbol_value = switch (placement) { |
| | 7868 | .progbits => |isi| .{ |
| | 7869 | .wrap(isi.node(elf)), |
| | 7870 | elf.getNodeShndx(isi.node(elf)), |
| | 7871 | input_sym.value, |
| | 7872 | }, |
| | 7873 | .bss => |bss| .{ |
| | 7874 | bss.shndx.get(elf).ni, |
| | 7875 | bss.shndx, |
| | 7876 | bss.shndx.vaddr(elf) + bss.offset + input_sym.value, |
| | 7877 | }, |
| | 7878 | .tbss => |tbss| .{ |
| | 7879 | tbss.shndx.get(elf).ni, |
| | 7880 | tbss.shndx, |
| | 7881 | switch (elf.ehdrType()) { |
| | 7882 | .REL => tbss.offset + input_sym.value, |
| | 7883 | .EXEC, .DYN => elf.tbssSegmentOffset() + |
| | 7884 | tbss.offset + |
| | 7885 | input_sym.value, |
| | 7886 | }, |
| | 7887 | }, |
| | 7888 | }; |
| 7723 | | 7889 | |
| 7724 | switch (input_sym.info.bind) { | 7890 | switch (input_sym.info.bind) { |
| 7725 | else => |bind| return diags.failParse( | 7891 | else => |bind| return diags.failParse( |
| ... | @@ -7729,20 +7895,20 @@ fn loadObject( | ... | @@ -7729,20 +7895,20 @@ fn loadObject( |
| 7729 | ), | 7895 | ), |
| 7730 | .LOCAL => { | 7896 | .LOCAL => { |
| 7731 | const lsi = try elf.addLocalSymbol(.{ | 7897 | const lsi = try elf.addLocalSymbol(.{ |
| 7732 | .node = .wrap(input_section_node), | 7898 | .node = symbol_oni, |
| 7733 | .name = name, | 7899 | .name = name, |
| 7734 | .value = input_sym.value, | 7900 | .value = symbol_value, |
| 7735 | .size = input_sym.size, | 7901 | .size = input_sym.size, |
| 7736 | .type = sym_type, | 7902 | .type = sym_type, |
| 7737 | .shndx = elf.getNodeShndx(input_section_node), | 7903 | .shndx = output_shndx, |
| 7738 | }); | 7904 | }); |
| 7739 | si.* = .local(lsi); | 7905 | si.* = .local(lsi); |
| 7740 | }, | 7906 | }, |
| 7741 | .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| { | 7907 | .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| { |
| 7742 | si.* = .global(elf.addGlobalSymbol(.{ | 7908 | si.* = .global(elf.addGlobalSymbol(.{ |
| 7743 | .node = .wrap(input_section_node), | 7909 | .node = symbol_oni, |
| 7744 | .name = name, | 7910 | .name = name, |
| 7745 | .value = input_sym.value, | 7911 | .value = symbol_value, |
| 7746 | .size = input_sym.size, | 7912 | .size = input_sym.size, |
| 7747 | .type = sym_type, | 7913 | .type = sym_type, |
| 7748 | .bind = switch (bind) { | 7914 | .bind = switch (bind) { |
| ... | @@ -7751,7 +7917,7 @@ fn loadObject( | ... | @@ -7751,7 +7917,7 @@ fn loadObject( |
| 7751 | else => unreachable, | 7917 | else => unreachable, |
| 7752 | }, | 7918 | }, |
| 7753 | .visibility = input_sym.other.visibility, | 7919 | .visibility = input_sym.other.visibility, |
| 7754 | .shndx = elf.getNodeShndx(input_section_node), | 7920 | .shndx = output_shndx, |
| 7755 | }) catch |err| switch (err) { | 7921 | }) catch |err| switch (err) { |
| 7756 | error.MultipleDefinitions => return diags.failParse( | 7922 | error.MultipleDefinitions => return diags.failParse( |
| 7757 | path, | 7923 | path, |
| ... | @@ -7783,7 +7949,15 @@ fn loadObject( | ... | @@ -7783,7 +7949,15 @@ fn loadObject( |
| 7783 | return diags.failParse(path, "unsupported rel entsize", .{}); | 7949 | return diags.failParse(path, "unsupported rel entsize", .{}); |
| 7784 | | 7950 | |
| 7785 | const loc_sec = &sections[rel_sec.shdr.info]; | 7951 | const loc_sec = &sections[rel_sec.shdr.info]; |
| 7786 | const loc_node = (loc_sec.isi orelse continue).node(elf); | 7952 | const loc_node = switch (loc_sec.placement orelse continue) { |
| | 7953 | .progbits => |isi| isi.node(elf), |
| | 7954 | .bss, .tbss => return diags.failParse( |
| | 7955 | path, |
| | 7956 | "relocations applying to BSS (SHT_NOBITS) sections are unsupported", |
| | 7957 | .{}, |
| | 7958 | ), |
| | 7959 | }; |
| | 7960 | |
| 7787 | elf.resetNodeRelocs(loc_node); | 7961 | elf.resetNodeRelocs(loc_node); |
| 7788 | | 7962 | |
| 7789 | const relnum = std.math.divExact( | 7963 | const relnum = std.math.divExact( |
| ... | @@ -7850,6 +8024,16 @@ fn loadObject( | ... | @@ -7850,6 +8024,16 @@ fn loadObject( |
| 7850 | }; | 8024 | }; |
| 7851 | }, | 8025 | }, |
| 7852 | }; | 8026 | }; |
| | 8027 | |
| | 8028 | if (input_has_bss) { |
| | 8029 | try elf.bss_inputs.append(gpa, input_index); |
| | 8030 | try elf.ni.data.resized(gpa, &elf.mf); |
| | 8031 | } |
| | 8032 | |
| | 8033 | if (input_has_tbss) { |
| | 8034 | try elf.tbss_inputs.append(gpa, input_index); |
| | 8035 | try elf.ni.tls.unwrap().?.resized(gpa, &elf.mf); |
| | 8036 | } |
| 7853 | }, | 8037 | }, |
| 7854 | } | 8038 | } |
| 7855 | } | 8039 | } |
| ... | @@ -8843,7 +9027,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -8843,7 +9027,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8843 | try elf.ensureSegmentAligned(phndx, opts.addralign); | 9027 | try elf.ensureSegmentAligned(phndx, opts.addralign); |
| 8844 | } | 9028 | } |
| 8845 | const gpa = elf.base.comp.gpa; | 9029 | const gpa = elf.base.comp.gpa; |
| 8846 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 9030 | if (opts.type != .NOBITS) { |
| | 9031 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| | 9032 | } |
| 8847 | try elf.shdrs.ensureUnusedCapacity(gpa, 1); | 9033 | try elf.shdrs.ensureUnusedCapacity(gpa, 1); |
| 8848 | const want_symbol = opts.flags.ALLOC or switch (opts.type) { | 9034 | const want_symbol = opts.flags.ALLOC or switch (opts.type) { |
| 8849 | .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL, | 9035 | .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL, |
| ... | @@ -8884,7 +9070,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -8884,7 +9070,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8884 | .EXEC, .DYN => segment_ni, | 9070 | .EXEC, .DYN => segment_ni, |
| 8885 | }; | 9071 | }; |
| 8886 | assert(opts.addralign.check(opts.size)); | 9072 | assert(opts.addralign.check(opts.size)); |
| 8887 | const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{ | 9073 | const oni: MappedFile.Node.Index.Optional = if (opts.type == .NOBITS) .none else .wrap(elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8888 | .size = opts.node_align.forward(opts.size), | 9074 | .size = opts.node_align.forward(opts.size), |
| 8889 | .alignment = opts.addralign.max(opts.node_align), | 9075 | .alignment = opts.addralign.max(opts.node_align), |
| 8890 | .resized = opts.size > 0, | 9076 | .resized = opts.size > 0, |
| ... | @@ -8892,18 +9078,18 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -8892,18 +9078,18 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8892 | }), switch (opts.manual_size) { | 9078 | }), switch (opts.manual_size) { |
| 8893 | false => .{ .section = shndx }, | 9079 | false => .{ .section = shndx }, |
| 8894 | true => .{ .section_manual_size = shndx }, | 9080 | true => .{ .section_manual_size = shndx }, |
| 8895 | }); | 9081 | })); |
| 8896 | const addr = elf.computeNodeVAddr(ni); | 9082 | const addr = if (oni.unwrap()) |ni| elf.computeNodeVAddr(ni) else 0; |
| 8897 | elf.shdrs.appendAssumeCapacity(.{ | 9083 | elf.shdrs.appendAssumeCapacity(.{ |
| 8898 | .lsi = if (want_symbol) try elf.addLocalSymbol(.{ | 9084 | .lsi = if (want_symbol) try elf.addLocalSymbol(.{ |
| 8899 | .node = ni.toOptional(), | 9085 | .node = oni, |
| 8900 | .name = "", | 9086 | .name = "", |
| 8901 | .value = addr, | 9087 | .value = addr, |
| 8902 | .size = 0, | 9088 | .size = 0, |
| 8903 | .type = .SECTION, | 9089 | .type = .SECTION, |
| 8904 | .shndx = shndx, | 9090 | .shndx = shndx, |
| 8905 | }) else .null, | 9091 | }) else .null, |
| 8906 | .ni = .wrap(ni), | 9092 | .ni = oni, |
| 8907 | .rela = switch (opts.type) { | 9093 | .rela = switch (opts.type) { |
| 8908 | .REL => unreachable, | 9094 | .REL => unreachable, |
| 8909 | .RELA => .{ .free_head = .none }, | 9095 | .RELA => .{ .free_head = .none }, |
| ... | @@ -8917,7 +9103,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -8917,7 +9103,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8917 | .type = opts.type, | 9103 | .type = opts.type, |
| 8918 | .flags = .{ .shf = opts.flags }, | 9104 | .flags = .{ .shf = opts.flags }, |
| 8919 | .addr = @intCast(addr), | 9105 | .addr = @intCast(addr), |
| 8920 | .offset = @intCast(elf.computeNodeElfOffset(ni)), | 9106 | .offset = if (oni.unwrap()) |ni| @intCast(elf.computeNodeElfOffset(ni)) else 0, |
| 8921 | .size = @intCast(opts.size), | 9107 | .size = @intCast(opts.size), |
| 8922 | .link = opts.link, | 9108 | .link = opts.link, |
| 8923 | .info = opts.info, | 9109 | .info = opts.info, |
| ... | @@ -11034,7 +11220,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -11034,7 +11220,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11034 | .DYNAMIC, | 11220 | .DYNAMIC, |
| 11035 | .INTERP, | 11221 | .INTERP, |
| 11036 | .PHDR, | 11222 | .PHDR, |
| 11037 | .TLS, | | |
| 11038 | .GNU_EH_FRAME, | 11223 | .GNU_EH_FRAME, |
| 11039 | .GNU_RELRO, | 11224 | .GNU_RELRO, |
| 11040 | => { | 11225 | => { |
| ... | @@ -11042,6 +11227,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -11042,6 +11227,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11042 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); | 11227 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| 11043 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); | 11228 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| 11044 | }, | 11229 | }, |
| | 11230 | |
| | 11231 | .TLS => { |
| | 11232 | const tbss_base = elf.tbssSegmentOffset(); |
| | 11233 | const new_vaddr = elf.computeNodeVAddr(ni); |
| | 11234 | const tls_offset = elf.targetLoad(&ph.offset); |
| | 11235 | const tls_filesz = elf.targetLoad(&ph.filesz); |
| | 11236 | |
| | 11237 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| | 11238 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| | 11239 | |
| | 11240 | // This may seem like a no-op since we're moving to and fro the same base, |
| | 11241 | // but we also need to update the section STT_SECTION symbol, which this |
| | 11242 | // function will conveniently do for us. |
| | 11243 | elf.updateNobitsAddress( |
| | 11244 | elf.shndx.tbss, |
| | 11245 | new_vaddr + tbss_base, |
| | 11246 | tls_offset + tls_filesz, |
| | 11247 | tbss_base, |
| | 11248 | tbss_base, |
| | 11249 | elf.tbss_inputs.items, |
| | 11250 | ); |
| | 11251 | }, |
| 11045 | } | 11252 | } |
| 11046 | }, | 11253 | }, |
| 11047 | } | 11254 | } |
| ... | @@ -11372,6 +11579,78 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -11372,6 +11579,78 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11372 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 11579 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11373 | } | 11580 | } |
| 11374 | | 11581 | |
| | 11582 | /// Update the position of a `NOBITS` section. |
| | 11583 | /// BSS needs an absolute symbol base, and TBSS needs TLS-segment-relative base. |
| | 11584 | fn updateNobitsAddress( |
| | 11585 | elf: *Elf, |
| | 11586 | shndx: Section.Index, |
| | 11587 | new_section_addr: u64, |
| | 11588 | new_file_offset: u64, |
| | 11589 | old_symbol_base: u64, |
| | 11590 | new_symbol_base: u64, |
| | 11591 | inputs: []const Node.InputIndex, |
| | 11592 | ) void { |
| | 11593 | assert(shndx != .UNDEF); |
| | 11594 | |
| | 11595 | switch (elf.shdrPtr(shndx)) { |
| | 11596 | inline else => |shdr| { |
| | 11597 | elf.targetStore(&shdr.addr, @intCast(new_section_addr)); |
| | 11598 | elf.targetStore(&shdr.offset, @intCast(new_file_offset)); |
| | 11599 | }, |
| | 11600 | } |
| | 11601 | |
| | 11602 | const expected_shndx = shndx.toSection().?; |
| | 11603 | |
| | 11604 | // Update local symbols. |
| | 11605 | for (inputs) |ii| { |
| | 11606 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| | 11607 | |
| | 11608 | while (lsi != end_lsi) : (lsi = @fromBackingInt( |
| | 11609 | @backingInt(lsi) + 1, |
| | 11610 | )) { |
| | 11611 | const symbol_shndx, const visibility = switch (elf.symPtr(lsi.index())) { |
| | 11612 | inline else => |sym| .{ |
| | 11613 | elf.targetLoad(&sym.shndx), |
| | 11614 | elf.targetLoad(&sym.other).visibility, |
| | 11615 | }, |
| | 11616 | }; |
| | 11617 | |
| | 11618 | if (symbol_shndx != expected_shndx) continue; |
| | 11619 | |
| | 11620 | switch (visibility) { |
| | 11621 | // These are globals demoted to STB_LOCAL and are updated below. |
| | 11622 | .HIDDEN, .INTERNAL => continue, |
| | 11623 | .PROTECTED => unreachable, |
| | 11624 | .DEFAULT => {}, |
| | 11625 | } |
| | 11626 | |
| | 11627 | const symbol: Symbol.Id = .local(lsi); |
| | 11628 | symbol.flushMoved( |
| | 11629 | elf, |
| | 11630 | symbol.value(elf) - old_symbol_base + new_symbol_base, |
| | 11631 | ); |
| | 11632 | } |
| | 11633 | } |
| | 11634 | |
| | 11635 | // Update globals. |
| | 11636 | // Since nobits sections have no nodes, we can't just iterate over `node_global_symbols`, |
| | 11637 | // so instead filter manually. |
| | 11638 | for (elf.globals.items, 0..) |global, global_index| { |
| | 11639 | if (global.symtab_index.ptr(elf).node != .none) continue; |
| | 11640 | const symbol: Symbol.Id = .global(@fromBackingInt(@intCast(global_index))); |
| | 11641 | const symbol_shndx = switch (elf.symPtr(global.symtab_index)) { |
| | 11642 | inline else => |sym| elf.targetLoad(&sym.shndx), |
| | 11643 | }; |
| | 11644 | if (symbol_shndx != expected_shndx) continue; |
| | 11645 | symbol.flushMoved(elf, symbol.value(elf) - old_symbol_base + new_symbol_base); |
| | 11646 | } |
| | 11647 | |
| | 11648 | Symbol.Id.local(shndx.get(elf).lsi).flushMoved( |
| | 11649 | elf, |
| | 11650 | new_section_addr, |
| | 11651 | ); |
| | 11652 | } |
| | 11653 | |
| 11375 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` | 11654 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` |
| 11376 | /// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and | 11655 | /// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and |
| 11377 | /// `memsz` fields of the segment, in order to place it at a valid virtual address. | 11656 | /// `memsz` fields of the segment, in order to place it at a valid virtual address. |
| ... | @@ -11400,22 +11679,21 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11400,22 +11679,21 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11400 | switch (elf.phdrSlice()) { | 11679 | switch (elf.phdrSlice()) { |
| 11401 | inline else => |phdr| { | 11680 | inline else => |phdr| { |
| 11402 | const offset = elf.targetLoad(&phdr[orig_phndx].offset); | 11681 | const offset = elf.targetLoad(&phdr[orig_phndx].offset); |
| 11403 | const size = elf.targetLoad(&phdr[orig_phndx].filesz); | 11682 | const filesz = elf.targetLoad(&phdr[orig_phndx].filesz); |
| 11404 | | | |
| 11405 | if (size == 0) { | | |
| 11406 | assert(elf.targetLoad(&phdr[orig_phndx].type) == .NULL); | | |
| 11407 | } else { | | |
| 11408 | assert(elf.targetLoad(&phdr[orig_phndx].type) == .LOAD); | | |
| 11409 | } | | |
| 11410 | | | |
| 11411 | elf.targetStore(&phdr[orig_phndx].memsz, size); | | |
| 11412 | elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits())); | | |
| 11413 | | 11683 | |
| 11414 | const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr); | 11684 | const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr); |
| 11415 | assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr); | 11685 | assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr); |
| 11416 | | 11686 | |
| | 11687 | const bss_size = if (segment_ni == elf.ni.data) |
| | 11688 | elf.shndx.bss.size(elf) |
| | 11689 | else |
| | 11690 | 0; |
| | 11691 | const memsz = filesz + bss_size; |
| | 11692 | |
| 11417 | var vaddr: u64 = orig_vaddr; | 11693 | var vaddr: u64 = orig_vaddr; |
| 11418 | | 11694 | |
| | 11695 | elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits())); |
| | 11696 | |
| 11419 | // First, we will shift the virtual address as needed in order to maintain the required | 11697 | // First, we will shift the virtual address as needed in order to maintain the required |
| 11420 | // property that vaddr is congruent to offset modulo the phdr alignment. | 11698 | // property that vaddr is congruent to offset modulo the phdr alignment. |
| 11421 | { | 11699 | { |
| ... | @@ -11459,7 +11737,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11459,7 +11737,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11459 | // the segment is already known to be moving---making it easier to grow in-place is | 11737 | // the segment is already known to be moving---making it easier to grow in-place is |
| 11460 | // the whole point of the multiplier! | 11738 | // the whole point of the multiplier! |
| 11461 | { | 11739 | { |
| 11462 | const target_size = if (vaddr == orig_vaddr) size else size * reserve_size_multiplier; | 11740 | const target_size = if (vaddr == orig_vaddr) memsz else memsz * reserve_size_multiplier; |
| 11463 | if (vaddr + target_size <= next_page_vaddr) { | 11741 | if (vaddr + target_size <= next_page_vaddr) { |
| 11464 | break; // hooray, we fit here! | 11742 | break; // hooray, we fit here! |
| 11465 | } | 11743 | } |
| ... | @@ -11481,7 +11759,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11481,7 +11759,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11481 | else => {}, | 11759 | else => {}, |
| 11482 | }; | 11760 | }; |
| 11483 | | 11761 | |
| 11484 | const free_vaddr = vaddr + size * reserve_size_multiplier; | 11762 | const free_vaddr = vaddr + memsz * reserve_size_multiplier; |
| 11485 | | 11763 | |
| 11486 | const next_align = page_align.max(next_ni.alignment(&elf.mf)); | 11764 | const next_align = page_align.max(next_ni.alignment(&elf.mf)); |
| 11487 | const next_offset = elf.targetLoad(&next_ph.offset); | 11765 | const next_offset = elf.targetLoad(&next_ph.offset); |
| ... | @@ -11491,6 +11769,21 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11491,6 +11769,21 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11491 | // will update the vaddr of `phndx` when we break from the loop. | 11769 | // will update the vaddr of `phndx` when we break from the loop. |
| 11492 | elf.targetStore(&next_ph.vaddr, @intCast(next_new_vaddr)); | 11770 | elf.targetStore(&next_ph.vaddr, @intCast(next_new_vaddr)); |
| 11493 | elf.targetStore(&next_ph.paddr, @intCast(next_new_vaddr)); | 11771 | elf.targetStore(&next_ph.paddr, @intCast(next_new_vaddr)); |
| | 11772 | |
| | 11773 | const bss_shndx = elf.shndx.bss; |
| | 11774 | const next_filesz = elf.targetLoad(&next_ph.filesz); |
| | 11775 | const old_bss_addr = bss_shndx.vaddr(elf); |
| | 11776 | const new_bss_addr = next_new_vaddr + next_filesz; |
| | 11777 | |
| | 11778 | elf.updateNobitsAddress( |
| | 11779 | bss_shndx, |
| | 11780 | new_bss_addr, |
| | 11781 | next_offset + next_filesz, |
| | 11782 | old_bss_addr, |
| | 11783 | new_bss_addr, |
| | 11784 | elf.bss_inputs.items, |
| | 11785 | ); |
| | 11786 | |
| 11494 | try next_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 11787 | try next_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11495 | | 11788 | |
| 11496 | break; | 11789 | break; |
| ... | @@ -11518,6 +11811,27 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11518,6 +11811,27 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11518 | elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr)); | 11811 | elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr)); |
| 11519 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 11812 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11520 | } | 11813 | } |
| | 11814 | |
| | 11815 | const ph = &phdr[phndx]; |
| | 11816 | |
| | 11817 | elf.targetStore(&ph.memsz, @intCast(memsz)); |
| | 11818 | elf.targetStore(&ph.type, if (memsz > 0) .LOAD else .NULL); |
| | 11819 | |
| | 11820 | if (segment_ni == elf.ni.data and elf.shndx.bss != .UNDEF) { |
| | 11821 | const bss_shndx = elf.shndx.bss; |
| | 11822 | |
| | 11823 | const old_bss_addr = bss_shndx.vaddr(elf); |
| | 11824 | const new_bss_addr = vaddr + filesz; |
| | 11825 | |
| | 11826 | elf.updateNobitsAddress( |
| | 11827 | bss_shndx, |
| | 11828 | new_bss_addr, |
| | 11829 | offset + filesz, |
| | 11830 | old_bss_addr, |
| | 11831 | new_bss_addr, |
| | 11832 | elf.bss_inputs.items, |
| | 11833 | ); |
| | 11834 | } |
| 11521 | }, | 11835 | }, |
| 11522 | } | 11836 | } |
| 11523 | } | 11837 | } |
| ... | @@ -11560,7 +11874,25 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -11560,7 +11874,25 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 11560 | elf.targetStore(&ph.memsz, @intCast(size)); | 11874 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 11561 | }, | 11875 | }, |
| 11562 | .TLS => { | 11876 | .TLS => { |
| 11563 | elf.targetStore(&ph.memsz, @intCast(size)); | 11877 | const tls_filesz: u64 = size; |
| | 11878 | |
| | 11879 | const old_tbss_base = elf.tbssSegmentOffset(); |
| | 11880 | const new_tbss_base = tls_filesz; |
| | 11881 | const tbss_size = elf.shndx.tbss.size(elf); |
| | 11882 | const tls_vaddr = elf.targetLoad(&ph.vaddr); |
| | 11883 | const tls_offset = elf.targetLoad(&ph.offset); |
| | 11884 | |
| | 11885 | elf.targetStore(&ph.memsz, @intCast(tls_filesz + tbss_size)); |
| | 11886 | |
| | 11887 | elf.updateNobitsAddress( |
| | 11888 | elf.shndx.tbss, |
| | 11889 | tls_vaddr + new_tbss_base, |
| | 11890 | tls_offset + new_tbss_base, |
| | 11891 | old_tbss_base, |
| | 11892 | new_tbss_base, |
| | 11893 | elf.tbss_inputs.items, |
| | 11894 | ); |
| | 11895 | |
| 11564 | // TPOFF relocations care about the size of the TLS segment. Re-apply | 11896 | // TPOFF relocations care about the size of the TLS segment. Re-apply |
| 11565 | // those, and also update any GOT entries from GOTTPOFF relocations. | 11897 | // those, and also update any GOT entries from GOTTPOFF relocations. |
| 11566 | for (elf.tls_size_symbol_relocs.keys()) |reloc| { | 11898 | for (elf.tls_size_symbol_relocs.keys()) |reloc| { |