| ... | @@ -151,6 +151,11 @@ bss_inputs: std.ArrayList(Node.InputIndex), | ... | @@ -151,6 +151,11 @@ bss_inputs: std.ArrayList(Node.InputIndex), |
| 151 | /// symbols when the address of `.tbss` changes. | 151 | /// symbols when the address of `.tbss` changes. |
| 152 | tbss_inputs: std.ArrayList(Node.InputIndex), | 152 | tbss_inputs: std.ArrayList(Node.InputIndex), |
| 153 | | 153 | |
| | 154 | /// Indicates that the address of the `.bss` section needs to be updated. |
| | 155 | /// |
| | 156 | /// Equivalent to a `PROGBITS` section's `MappedFile.Node` being marked as "moved". |
| | 157 | bss_moved: bool, |
| | 158 | |
| 154 | shstrtab: StringTable, | 159 | shstrtab: StringTable, |
| 155 | strtab: StringTable, | 160 | strtab: StringTable, |
| 156 | dynstr: StringTable, | 161 | dynstr: StringTable, |
| ... | @@ -4815,6 +4820,7 @@ fn create( | ... | @@ -4815,6 +4820,7 @@ fn create( |
| 4815 | .tbss_globals = .empty, | 4820 | .tbss_globals = .empty, |
| 4816 | .bss_inputs = .empty, | 4821 | .bss_inputs = .empty, |
| 4817 | .tbss_inputs = .empty, | 4822 | .tbss_inputs = .empty, |
| | 4823 | .bss_moved = false, |
| 4818 | .shstrtab = .{ .map = .empty }, | 4824 | .shstrtab = .{ .map = .empty }, |
| 4819 | .strtab = .{ .map = .empty }, | 4825 | .strtab = .{ .map = .empty }, |
| 4820 | .dynstr = .{ .map = .empty }, | 4826 | .dynstr = .{ .map = .empty }, |
| ... | @@ -6426,20 +6432,12 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | ... | @@ -6426,20 +6432,12 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 6426 | }; | 6432 | }; |
| 6427 | } | 6433 | } |
| 6428 | | 6434 | |
| 6429 | fn tbssBaseOffset(elf: *Elf) u64 { | 6435 | fn tbssOffset(elf: *Elf) u64 { |
| 6430 | const tbss_addr = elf.shndx.tbss.vaddr(elf); | 6436 | // The `.tbss` section is placed exactly at the end of the TLS segment. |
| 6431 | | 6437 | const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment; |
| 6432 | // Hasn't been laid out yet. | 6438 | return switch (elf.phdrSlice()) { |
| 6433 | if (tbss_addr == 0 or elf.ehdrType() == .REL) return 0; | 6439 | inline else => |phdr| elf.targetLoad(&phdr[tls_phndx].filesz), |
| 6434 | | | |
| 6435 | const tls_ni = elf.ni.tls.unwrap().?; | | |
| 6436 | const tls_phndx = elf.getNode(tls_ni).segment; | | |
| 6437 | | | |
| 6438 | const tls_vaddr = switch (elf.phdrSlice()) { | | |
| 6439 | inline else => |phdr| elf.targetLoad(&phdr[tls_phndx].vaddr), | | |
| 6440 | }; | 6440 | }; |
| 6441 | | | |
| 6442 | return tbss_addr - tls_vaddr; | | |
| 6443 | } | 6441 | } |
| 6444 | | 6442 | |
| 6445 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | 6443 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| ... | @@ -7921,7 +7919,7 @@ fn loadObject( | ... | @@ -7921,7 +7919,7 @@ fn loadObject( |
| 7921 | if (elf.ni.tls != .none and | 7919 | if (elf.ni.tls != .none and |
| 7922 | nobits.shndx == elf.shndx.tbss) | 7920 | nobits.shndx == elf.shndx.tbss) |
| 7923 | { | 7921 | { |
| 7924 | break :base elf.tbssBaseOffset(); | 7922 | break :base elf.tbssOffset(); |
| 7925 | } | 7923 | } |
| 7926 | assert(nobits.shndx == elf.shndx.bss); | 7924 | assert(nobits.shndx == elf.shndx.bss); |
| 7927 | break :base nobits.shndx.vaddr(elf); | 7925 | break :base nobits.shndx.vaddr(elf); |
| ... | @@ -10871,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool { | ... | @@ -10871,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool { |
| 10871 | if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni); | 10869 | if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni); |
| 10872 | break :task; | 10870 | break :task; |
| 10873 | } | 10871 | } |
| | 10872 | if (elf.bss_moved) { |
| | 10873 | elf.bss_moved = false; |
| | 10874 | |
| | 10875 | const data_phndx = elf.getNode(elf.ni.data).segment; |
| | 10876 | const data_offset: u64, const data_vaddr: u64, const data_filesz: u64 = switch (elf.phdrSlice()) { |
| | 10877 | inline else => |phdr| .{ |
| | 10878 | elf.targetLoad(&phdr[data_phndx].offset), |
| | 10879 | elf.targetLoad(&phdr[data_phndx].vaddr), |
| | 10880 | elf.targetLoad(&phdr[data_phndx].filesz), |
| | 10881 | }, |
| | 10882 | }; |
| | 10883 | |
| | 10884 | const old_bss_addr = elf.shndx.bss.vaddr(elf); |
| | 10885 | const new_bss_addr = data_vaddr + data_filesz; |
| | 10886 | |
| | 10887 | const bss_section_sym: Symbol.Id = .local(elf.shndx.bss.get(elf).lsi); |
| | 10888 | bss_section_sym.flushMoved(elf, new_bss_addr); |
| | 10889 | switch (elf.shdrPtr(elf.shndx.bss)) { |
| | 10890 | inline else => |shdr| { |
| | 10891 | elf.targetStore(&shdr.offset, @intCast(data_offset + data_filesz)); |
| | 10892 | elf.targetStore(&shdr.addr, @intCast(new_bss_addr)); |
| | 10893 | }, |
| | 10894 | } |
| | 10895 | elf.flushMovedNobitsSymbols( |
| | 10896 | elf.shndx.bss, |
| | 10897 | old_bss_addr, |
| | 10898 | new_bss_addr, |
| | 10899 | elf.bss_inputs.items, |
| | 10900 | elf.bss_globals.keys(), |
| | 10901 | ); |
| | 10902 | |
| | 10903 | break :task; |
| | 10904 | } |
| 10874 | } | 10905 | } |
| 10875 | if (elf.inputs.items.len - elf.input_pending_index > 0) return true; | 10906 | if (elf.inputs.items.len - elf.input_pending_index > 0) return true; |
| 10876 | if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true; | 10907 | if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true; |
| 10877 | if (elf.one_shot_fixups.items.len > 0) return true; | 10908 | if (elf.one_shot_fixups.items.len > 0) return true; |
| 10878 | if (elf.changed_symtab_index.count() > 0) return true; | 10909 | if (elf.changed_symtab_index.count() > 0) return true; |
| 10879 | if (elf.mf.updates.items.len > 0) return true; | 10910 | if (elf.mf.updates.items.len > 0) return true; |
| | 10911 | if (elf.bss_moved) return true; |
| 10880 | return false; | 10912 | return false; |
| 10881 | } | 10913 | } |
| 10882 | | 10914 | |
| ... | @@ -11231,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { | ... | @@ -11231,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 11231 | inline else => |phdr, class| { | 11263 | inline else => |phdr, class| { |
| 11232 | const ph = &phdr[phndx]; | 11264 | const ph = &phdr[phndx]; |
| 11233 | elf.targetStore(&ph.offset, @intCast(elf_offset)); | 11265 | elf.targetStore(&ph.offset, @intCast(elf_offset)); |
| 11234 | if (elf.targetLoad(&ph.type) == .PHDR) { | 11266 | switch (elf.targetLoad(&ph.type)) { |
| 11235 | @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset; | 11267 | .PHDR => { |
| | 11268 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); |
| | 11269 | elf.targetStore(&ehdr.phoff, @intCast(elf_offset)); |
| | 11270 | }, |
| | 11271 | .TLS => { |
| | 11272 | // The `.tbss` section's offset should be at the end of the TLS segment. |
| | 11273 | const tls_filesz = elf.targetLoad(&ph.filesz); |
| | 11274 | const tbss_shdr = @field(elf.shdrPtr(elf.shndx.tbss), @tagName(class)); |
| | 11275 | elf.targetStore(&tbss_shdr.offset, @intCast(elf_offset + tls_filesz)); |
| | 11276 | }, |
| | 11277 | else => if (ni == elf.ni.data) { |
| | 11278 | // The `.bss` section's offset should be at the end of the data segment. |
| | 11279 | const data_filesz = elf.targetLoad(&ph.filesz); |
| | 11280 | const bss_shdr = @field(elf.shdrPtr(elf.shndx.bss), @tagName(class)); |
| | 11281 | elf.targetStore(&bss_shdr.offset, @intCast(elf_offset + data_filesz)); |
| | 11282 | }, |
| 11236 | } | 11283 | } |
| 11237 | }, | 11284 | }, |
| 11238 | } | 11285 | } |
| ... | @@ -11283,23 +11330,16 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -11283,23 +11330,16 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11283 | }, | 11330 | }, |
| 11284 | | 11331 | |
| 11285 | .TLS => { | 11332 | .TLS => { |
| 11286 | const tbss_base = elf.tbssBaseOffset(); | | |
| 11287 | const new_vaddr = elf.computeNodeVAddr(ni); | 11333 | const new_vaddr = elf.computeNodeVAddr(ni); |
| 11288 | const tls_offset = elf.targetLoad(&ph.offset); | | |
| 11289 | const tls_filesz = elf.targetLoad(&ph.filesz); | | |
| 11290 | | | |
| 11291 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); | 11334 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| 11292 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); | 11335 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| 11293 | | 11336 | |
| 11294 | const tbss_shndx = elf.shndx.tbss; | 11337 | // Update the address of the `.tbss` section at the end of this segment: |
| 11295 | const tbss_addr = new_vaddr + tbss_base; | 11338 | const tbss_addr = new_vaddr + elf.tbssOffset(); |
| 11296 | switch (elf.shdrPtr(tbss_shndx)) { | 11339 | switch (elf.shdrPtr(elf.shndx.tbss)) { |
| 11297 | inline else => |shdr| { | 11340 | inline else => |shdr| elf.targetStore(&shdr.addr, @intCast(tbss_addr)), |
| 11298 | elf.targetStore(&shdr.addr, @intCast(tbss_addr)); | | |
| 11299 | elf.targetStore(&shdr.offset, @intCast(tls_offset + tls_filesz)); | | |
| 11300 | }, | | |
| 11301 | } | 11341 | } |
| 11302 | Symbol.Id.local(tbss_shndx.get(elf).lsi).flushMoved( | 11342 | Symbol.Id.local(elf.shndx.tbss.get(elf).lsi).flushMoved( |
| 11303 | elf, | 11343 | elf, |
| 11304 | tbss_addr, | 11344 | tbss_addr, |
| 11305 | ); | 11345 | ); |
| ... | @@ -11634,13 +11674,15 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -11634,13 +11674,15 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11634 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 11674 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11635 | } | 11675 | } |
| 11636 | | 11676 | |
| 11637 | /// Update the position of a `NOBITS` section. | 11677 | /// Update the value of all symbols in a `NOBITS` section. All symbol values are updated to |
| 11638 | /// BSS needs an absolute symbol base, and TBSS needs TLS-segment-relative base. | 11678 | /// `old_value - old_symbol_base + new_symbol_base`. |
| 11639 | fn updateNobitsAddress( | 11679 | /// |
| | 11680 | /// For `.bss`, the symbol base is the section's virtual address. |
| | 11681 | /// |
| | 11682 | /// For `.tbss`, the symbol base is the offset into the TLS segment. |
| | 11683 | fn flushMovedNobitsSymbols( |
| 11640 | elf: *Elf, | 11684 | elf: *Elf, |
| 11641 | shndx: Section.Index, | 11685 | shndx: Section.Index, |
| 11642 | new_section_addr: u64, | | |
| 11643 | new_file_offset: u64, | | |
| 11644 | old_symbol_base: u64, | 11686 | old_symbol_base: u64, |
| 11645 | new_symbol_base: u64, | 11687 | new_symbol_base: u64, |
| 11646 | inputs: []const Node.InputIndex, | 11688 | inputs: []const Node.InputIndex, |
| ... | @@ -11648,13 +11690,6 @@ fn updateNobitsAddress( | ... | @@ -11648,13 +11690,6 @@ fn updateNobitsAddress( |
| 11648 | ) void { | 11690 | ) void { |
| 11649 | assert(shndx != .UNDEF); | 11691 | assert(shndx != .UNDEF); |
| 11650 | | 11692 | |
| 11651 | switch (elf.shdrPtr(shndx)) { | | |
| 11652 | inline else => |shdr| { | | |
| 11653 | elf.targetStore(&shdr.addr, @intCast(new_section_addr)); | | |
| 11654 | elf.targetStore(&shdr.offset, @intCast(new_file_offset)); | | |
| 11655 | }, | | |
| 11656 | } | | |
| 11657 | | | |
| 11658 | // Update local symbols. | 11693 | // Update local symbols. |
| 11659 | for (inputs) |ii| { | 11694 | for (inputs) |ii| { |
| 11660 | var lsi, const end_lsi = ii.localSymbolRange(elf); | 11695 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| ... | @@ -11662,14 +11697,14 @@ fn updateNobitsAddress( | ... | @@ -11662,14 +11697,14 @@ fn updateNobitsAddress( |
| 11662 | while (lsi != end_lsi) : (lsi = @fromBackingInt( | 11697 | while (lsi != end_lsi) : (lsi = @fromBackingInt( |
| 11663 | @backingInt(lsi) + 1, | 11698 | @backingInt(lsi) + 1, |
| 11664 | )) { | 11699 | )) { |
| 11665 | const symbol_shndx: Section.Index, const visibility = switch (elf.symPtr(lsi.index())) { | 11700 | const sym_shndx: Section.Index, const visibility = switch (elf.symPtr(lsi.index())) { |
| 11666 | inline else => |sym| .{ | 11701 | inline else => |sym| .{ |
| 11667 | .fromSection(elf.targetLoad(&sym.shndx)), | 11702 | .fromSection(elf.targetLoad(&sym.shndx)), |
| 11668 | elf.targetLoad(&sym.other).visibility, | 11703 | elf.targetLoad(&sym.other).visibility, |
| 11669 | }, | 11704 | }, |
| 11670 | }; | 11705 | }; |
| 11671 | | 11706 | |
| 11672 | if (symbol_shndx != shndx) continue; | 11707 | if (sym_shndx != shndx) continue; |
| 11673 | | 11708 | |
| 11674 | switch (visibility) { | 11709 | switch (visibility) { |
| 11675 | // These are globals demoted to STB_LOCAL and are updated below. | 11710 | // These are globals demoted to STB_LOCAL and are updated below. |
| ... | @@ -11700,40 +11735,26 @@ fn updateNobitsAddress( | ... | @@ -11700,40 +11735,26 @@ fn updateNobitsAddress( |
| 11700 | symbol.value(elf) - old_symbol_base + new_symbol_base, | 11735 | symbol.value(elf) - old_symbol_base + new_symbol_base, |
| 11701 | ); | 11736 | ); |
| 11702 | } | 11737 | } |
| 11703 | | | |
| 11704 | Symbol.Id.local(shndx.get(elf).lsi).flushMoved( | | |
| 11705 | elf, | | |
| 11706 | new_section_addr, | | |
| 11707 | ); | | |
| 11708 | } | 11738 | } |
| 11709 | | 11739 | |
| 11710 | fn loadSegmentChildrenMoved( | 11740 | /// Updates `vaddr` and `paddr` of the segment header, and marks everything in the segment as moved. |
| | 11741 | fn updateSegmentLoadAddress( |
| 11711 | elf: *Elf, | 11742 | elf: *Elf, |
| 11712 | segment_ni: MappedFile.Node.Index, | 11743 | segment_ni: MappedFile.Node.Index, |
| 11713 | old_vaddr: u64, | | |
| 11714 | new_vaddr: u64, | 11744 | new_vaddr: u64, |
| 11715 | offset: u64, | | |
| 11716 | filesz: u64, | | |
| 11717 | ) std.mem.Allocator.Error!void { | 11745 | ) std.mem.Allocator.Error!void { |
| 11718 | if (segment_ni == elf.ni.data) { | 11746 | const phndx = elf.getNode(segment_ni).segment; |
| 11719 | const bss_shndx = elf.shndx.bss; | | |
| 11720 | const old_bss_addr = bss_shndx.vaddr(elf); | | |
| 11721 | const new_bss_addr = new_vaddr + filesz; | | |
| 11722 | | | |
| 11723 | elf.updateNobitsAddress( | | |
| 11724 | bss_shndx, | | |
| 11725 | new_bss_addr, | | |
| 11726 | offset + filesz, | | |
| 11727 | old_bss_addr, | | |
| 11728 | new_bss_addr, | | |
| 11729 | elf.bss_inputs.items, | | |
| 11730 | elf.bss_globals.keys(), | | |
| 11731 | ); | | |
| 11732 | } | | |
| 11733 | | 11747 | |
| 11734 | if (old_vaddr != new_vaddr) { | 11748 | switch (elf.phdrSlice()) { |
| 11735 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 11749 | inline else => |phdr| { |
| | 11750 | assert(new_vaddr != elf.targetLoad(&phdr[phndx].vaddr)); |
| | 11751 | elf.targetStore(&phdr[phndx].vaddr, @intCast(new_vaddr)); |
| | 11752 | elf.targetStore(&phdr[phndx].paddr, @intCast(new_vaddr)); |
| | 11753 | }, |
| 11736 | } | 11754 | } |
| | 11755 | |
| | 11756 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| | 11757 | if (segment_ni == elf.ni.data) elf.bss_moved = true; |
| 11737 | } | 11758 | } |
| 11738 | | 11759 | |
| 11739 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` | 11760 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` |
| ... | @@ -11852,19 +11873,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11852,19 +11873,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11852 | const next_offset = elf.targetLoad(&next_ph.offset); | 11873 | const next_offset = elf.targetLoad(&next_ph.offset); |
| 11853 | const next_new_vaddr = next_align.forward(free_vaddr) + next_offset % next_align.toByteUnits(); | 11874 | const next_new_vaddr = next_align.forward(free_vaddr) + next_offset % next_align.toByteUnits(); |
| 11854 | | 11875 | |
| 11855 | // This logic for updating the data segment's vaddr is identical to how we | 11876 | try elf.updateSegmentLoadAddress(next_ni, next_new_vaddr); |
| 11856 | // will update the vaddr of `phndx` when we break from the loop. | | |
| 11857 | elf.targetStore(&next_ph.vaddr, @intCast(next_new_vaddr)); | | |
| 11858 | elf.targetStore(&next_ph.paddr, @intCast(next_new_vaddr)); | | |
| 11859 | | | |
| 11860 | const next_filesz = elf.targetLoad(&next_ph.filesz); | | |
| 11861 | try elf.loadSegmentChildrenMoved( | | |
| 11862 | next_ni, | | |
| 11863 | next_vaddr, | | |
| 11864 | next_new_vaddr, | | |
| 11865 | next_offset, | | |
| 11866 | next_filesz, | | |
| 11867 | ); | | |
| 11868 | | 11877 | |
| 11869 | break; | 11878 | break; |
| 11870 | }, | 11879 | }, |
| ... | @@ -11887,17 +11896,8 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro | ... | @@ -11887,17 +11896,8 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11887 | } | 11896 | } |
| 11888 | | 11897 | |
| 11889 | if (vaddr != orig_vaddr) { | 11898 | if (vaddr != orig_vaddr) { |
| 11890 | elf.targetStore(&phdr[phndx].vaddr, @intCast(vaddr)); | 11899 | try elf.updateSegmentLoadAddress(segment_ni, vaddr); |
| 11891 | elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr)); | | |
| 11892 | } | 11900 | } |
| 11893 | | | |
| 11894 | try elf.loadSegmentChildrenMoved( | | |
| 11895 | segment_ni, | | |
| 11896 | orig_vaddr, | | |
| 11897 | vaddr, | | |
| 11898 | offset, | | |
| 11899 | filesz, | | |
| 11900 | ); | | |
| 11901 | }, | 11901 | }, |
| 11902 | } | 11902 | } |
| 11903 | } | 11903 | } |
| ... | @@ -11926,40 +11926,46 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -11926,40 +11926,46 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 11926 | .ehdr => unreachable, | 11926 | .ehdr => unreachable, |
| 11927 | .shdr => {}, | 11927 | .shdr => {}, |
| 11928 | .segment => |phndx| switch (elf.phdrSlice()) { | 11928 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 11929 | inline else => |phdr| { | 11929 | inline else => |phdr, class| { |
| 11930 | assert(elf.phdrs.items[phndx].unwrap().? == ni); | 11930 | assert(elf.phdrs.items[phndx].unwrap().? == ni); |
| 11931 | const ph = &phdr[phndx]; | 11931 | const ph = &phdr[phndx]; |
| 11932 | elf.targetStore(&ph.filesz, @intCast(size)); | | |
| 11933 | switch (elf.targetLoad(&ph.type)) { | 11932 | switch (elf.targetLoad(&ph.type)) { |
| 11934 | else => unreachable, | 11933 | else => unreachable, |
| 11935 | .NULL, .LOAD => { | 11934 | .NULL, .LOAD => { |
| | 11935 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11936 | try elf.allocateSegmentLoadAddress(phndx); | 11936 | try elf.allocateSegmentLoadAddress(phndx); |
| | 11937 | if (ni == elf.ni.data) elf.bss_moved = true; |
| 11937 | }, | 11938 | }, |
| 11938 | .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => { | 11939 | .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => { |
| | 11940 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11939 | elf.targetStore(&ph.memsz, @intCast(size)); | 11941 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 11940 | }, | 11942 | }, |
| 11941 | .TLS => { | 11943 | .TLS => { |
| 11942 | const tls_filesz: u64 = size; | 11944 | // We must fetch this value before modifying our `filesz`. |
| | 11945 | const old_tbss_offset = elf.tbssOffset(); |
| 11943 | | 11946 | |
| 11944 | const old_tbss_base = elf.tbssBaseOffset(); | 11947 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11945 | const new_tbss_base = tls_filesz; | | |
| 11946 | const tbss_size = elf.shndx.tbss.size(elf); | | |
| 11947 | const tls_vaddr = elf.targetLoad(&ph.vaddr); | | |
| 11948 | const tls_offset = elf.targetLoad(&ph.offset); | | |
| 11949 | | 11948 | |
| 11950 | const tls_memsz = std.mem.alignForward( | 11949 | // Our memsz must include the `.tbss` section. |
| 11951 | u64, | 11950 | const tls_align: Alignment = .fromByteUnits(elf.targetLoad(&ph.@"align")); |
| 11952 | tls_filesz + tbss_size, | 11951 | elf.targetStore(&ph.memsz, @intCast( |
| 11953 | elf.targetLoad(&ph.@"align"), | 11952 | tls_align.forward(size + elf.shndx.tbss.size(elf)), |
| 11954 | ); | 11953 | )); |
| 11955 | elf.targetStore(&ph.memsz, @intCast(tls_memsz)); | | |
| 11956 | | 11954 | |
| 11957 | elf.updateNobitsAddress( | 11955 | // `.tbss` section goes at the end of this segment. Update its offset: |
| | 11956 | const tls_offset = elf.targetLoad(&ph.offset); |
| | 11957 | const tbss_shdr = @field(elf.shdrPtr(elf.shndx.tbss), @tagName(class)); |
| | 11958 | elf.targetStore(&tbss_shdr.offset, @intCast(tls_offset + size)); |
| | 11959 | // and its address: |
| | 11960 | const tls_vaddr = elf.targetLoad(&ph.vaddr); |
| | 11961 | const tbss_section_sym: Symbol.Id = .local(elf.shndx.tbss.get(elf).lsi); |
| | 11962 | tbss_section_sym.flushMoved(elf, tls_vaddr + size); |
| | 11963 | elf.targetStore(&tbss_shdr.addr, @intCast(tls_vaddr + size)); |
| | 11964 | // and update the values of symbols in that section: |
| | 11965 | elf.flushMovedNobitsSymbols( |
| 11958 | elf.shndx.tbss, | 11966 | elf.shndx.tbss, |
| 11959 | tls_vaddr + new_tbss_base, | 11967 | old_tbss_offset, |
| 11960 | tls_offset + new_tbss_base, | 11968 | size, |
| 11961 | old_tbss_base, | | |
| 11962 | new_tbss_base, | | |
| 11963 | elf.tbss_inputs.items, | 11969 | elf.tbss_inputs.items, |
| 11964 | elf.tbss_globals.keys(), | 11970 | elf.tbss_globals.keys(), |
| 11965 | ); | 11971 | ); |