| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | base: link.File, | 1 | base: link.File, |
| | 2 | |
| 2 | dwarf: ?Dwarf = null, | 3 | dwarf: ?Dwarf = null, |
| 3 | | 4 | |
| 4 | ptr_width: PtrWidth, | 5 | ptr_width: PtrWidth, |
| ... | @@ -103,6 +104,7 @@ phdr_table_dirty: bool = false, | ... | @@ -103,6 +104,7 @@ phdr_table_dirty: bool = false, |
| 103 | shdr_table_dirty: bool = false, | 104 | shdr_table_dirty: bool = false, |
| 104 | shstrtab_dirty: bool = false, | 105 | shstrtab_dirty: bool = false, |
| 105 | strtab_dirty: bool = false, | 106 | strtab_dirty: bool = false, |
| | 107 | got_dirty: bool = false, |
| 106 | | 108 | |
| 107 | debug_strtab_dirty: bool = false, | 109 | debug_strtab_dirty: bool = false, |
| 108 | debug_abbrev_section_dirty: bool = false, | 110 | debug_abbrev_section_dirty: bool = false, |
| ... | @@ -411,21 +413,31 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { | ... | @@ -411,21 +413,31 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 411 | const AllocateSegmentOpts = struct { | 413 | const AllocateSegmentOpts = struct { |
| 412 | size: u64, | 414 | size: u64, |
| 413 | alignment: u64, | 415 | alignment: u64, |
| 414 | addr: ?u64 = null, // TODO find free VM space | 416 | addr: ?u64 = null, |
| 415 | flags: u32 = elf.PF_R, | 417 | flags: u32 = elf.PF_R, |
| 416 | }; | 418 | }; |
| 417 | | 419 | |
| 418 | pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 { | 420 | pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 { |
| | 421 | const gpa = self.base.allocator; |
| 419 | const index = @as(u16, @intCast(self.phdrs.items.len)); | 422 | const index = @as(u16, @intCast(self.phdrs.items.len)); |
| 420 | try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1); | 423 | try self.phdrs.ensureUnusedCapacity(gpa, 1); |
| 421 | const off = self.findFreeSpace(opts.size, opts.alignment); | 424 | const off = self.findFreeSpace(opts.size, opts.alignment); |
| 422 | // Memory is always allocated in sequence. | 425 | // Currently, we automatically allocate memory in sequence by finding the largest |
| 423 | // TODO is this correct? Or should we implement something similar to `findFreeSpace`? | 426 | // allocated virtual address and going from there. |
| 424 | // How would that impact HCS? | 427 | // TODO we want to keep machine code segment in the furthest memory range among all |
| | 428 | // segments as it is most likely to grow. |
| 425 | const addr = opts.addr orelse blk: { | 429 | const addr = opts.addr orelse blk: { |
| 426 | assert(self.phdr_table_load_index != null); | 430 | const reserved_capacity = self.calcImageBase() * 4; |
| 427 | const phdr = &self.phdrs.items[index - 1]; | 431 | // Calculate largest VM address |
| 428 | break :blk mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, opts.alignment); | 432 | const count = self.phdrs.items.len; |
| | 433 | var addresses = std.ArrayList(u64).init(gpa); |
| | 434 | defer addresses.deinit(); |
| | 435 | try addresses.ensureTotalCapacityPrecise(count); |
| | 436 | for (self.phdrs.items) |phdr| { |
| | 437 | addresses.appendAssumeCapacity(phdr.p_vaddr + reserved_capacity); |
| | 438 | } |
| | 439 | mem.sort(u64, addresses.items, {}, std.sort.asc(u64)); |
| | 440 | break :blk mem.alignForward(u64, addresses.items[count - 1], opts.alignment); |
| 429 | }; | 441 | }; |
| 430 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ | 442 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 431 | index, | 443 | index, |
| ... | @@ -530,6 +542,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -530,6 +542,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 530 | .p64 => false, | 542 | .p64 => false, |
| 531 | }; | 543 | }; |
| 532 | const ptr_size: u8 = self.ptrWidthBytes(); | 544 | const ptr_size: u8 = self.ptrWidthBytes(); |
| | 545 | const is_linux = self.base.options.target.os.tag == .linux; |
| | 546 | const large_addrspace = self.base.options.target.ptrBitWidth() >= 32; |
| 533 | const image_base = self.calcImageBase(); | 547 | const image_base = self.calcImageBase(); |
| 534 | | 548 | |
| 535 | if (self.phdr_table_index == null) { | 549 | if (self.phdr_table_index == null) { |
| ... | @@ -577,13 +591,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -577,13 +591,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 577 | } | 591 | } |
| 578 | | 592 | |
| 579 | if (self.phdr_got_index == null) { | 593 | if (self.phdr_got_index == null) { |
| 580 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. | 594 | const addr: u64 = if (large_addrspace) 0x4000000 else 0x8000; |
| 581 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something | | |
| 582 | // else in virtual memory. | | |
| 583 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000; | | |
| 584 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | 595 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 585 | // page align. | 596 | // page align. |
| 586 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | 597 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 587 | self.phdr_got_index = try self.allocateSegment(.{ | 598 | self.phdr_got_index = try self.allocateSegment(.{ |
| 588 | .addr = addr, | 599 | .addr = addr, |
| 589 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, | 600 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| ... | @@ -593,10 +604,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -593,10 +604,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 593 | } | 604 | } |
| 594 | | 605 | |
| 595 | if (self.phdr_load_ro_index == null) { | 606 | if (self.phdr_load_ro_index == null) { |
| 596 | // TODO Same as for GOT | 607 | const addr: u64 = if (large_addrspace) 0xc000000 else 0xa000; |
| 597 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; | 608 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 598 | // Same reason as for GOT | | |
| 599 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 600 | self.phdr_load_ro_index = try self.allocateSegment(.{ | 609 | self.phdr_load_ro_index = try self.allocateSegment(.{ |
| 601 | .addr = addr, | 610 | .addr = addr, |
| 602 | .size = 1024, | 611 | .size = 1024, |
| ... | @@ -606,10 +615,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -606,10 +615,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 606 | } | 615 | } |
| 607 | | 616 | |
| 608 | if (self.phdr_load_rw_index == null) { | 617 | if (self.phdr_load_rw_index == null) { |
| 609 | // TODO Same as for GOT | 618 | const addr: u64 = if (large_addrspace) 0x10000000 else 0xc000; |
| 610 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; | 619 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 611 | // Same reason as for GOT | | |
| 612 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 613 | self.phdr_load_rw_index = try self.allocateSegment(.{ | 620 | self.phdr_load_rw_index = try self.allocateSegment(.{ |
| 614 | .addr = addr, | 621 | .addr = addr, |
| 615 | .size = 1024, | 622 | .size = 1024, |
| ... | @@ -619,9 +626,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -619,9 +626,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 619 | } | 626 | } |
| 620 | | 627 | |
| 621 | if (self.phdr_load_zerofill_index == null) { | 628 | if (self.phdr_load_zerofill_index == null) { |
| 622 | // TODO Same as for GOT | 629 | const addr: u64 = if (large_addrspace) 0x14000000 else 0xf000; |
| 623 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; | 630 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 624 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 625 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ | 631 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ |
| 626 | .addr = addr, | 632 | .addr = addr, |
| 627 | .size = 0, | 633 | .size = 0, |
| ... | @@ -803,7 +809,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -803,7 +809,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 803 | } | 809 | } |
| 804 | | 810 | |
| 805 | if (self.base.options.module) |module| { | 811 | if (self.base.options.module) |module| { |
| 806 | if (self.zig_module_index == null) { | 812 | if (self.zig_module_index == null and !self.base.options.use_llvm) { |
| 807 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 813 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 808 | self.files.set(index, .{ .zig_module = .{ | 814 | self.files.set(index, .{ .zig_module = .{ |
| 809 | .index = index, | 815 | .index = index, |
| ... | @@ -858,7 +864,30 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -858,7 +864,30 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 858 | } | 864 | } |
| 859 | | 865 | |
| 860 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); | 866 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| 861 | assert(needed_size <= mem_capacity); // TODO grow section in virtual memory | 867 | if (needed_size > mem_capacity) { |
| | 868 | // We are exceeding our allocated VM capacity so we need to shift everything in memory |
| | 869 | // and grow. |
| | 870 | { |
| | 871 | const dirty_addr = phdr.p_vaddr + phdr.p_memsz; |
| | 872 | self.got_dirty = for (self.got.entries.items) |entry| { |
| | 873 | if (self.symbol(entry.symbol_index).value >= dirty_addr) break true; |
| | 874 | } else false; |
| | 875 | |
| | 876 | // TODO mark relocs dirty |
| | 877 | } |
| | 878 | try self.growSegment(shdr_index, needed_size); |
| | 879 | |
| | 880 | if (self.zig_module_index != null) { |
| | 881 | // TODO self-hosted backends cannot yet handle this condition correctly as the linker |
| | 882 | // cannot update emitted virtual addresses of symbols already committed to the final file. |
| | 883 | var err = try self.addErrorWithNotes(2); |
| | 884 | try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{ |
| | 885 | phdr_index, |
| | 886 | }); |
| | 887 | try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{}); |
| | 888 | try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{}); |
| | 889 | } |
| | 890 | } |
| 862 | | 891 | |
| 863 | shdr.sh_size = needed_size; | 892 | shdr.sh_size = needed_size; |
| 864 | phdr.p_memsz = needed_size; | 893 | phdr.p_memsz = needed_size; |
| ... | @@ -870,6 +899,62 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -870,6 +899,62 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 870 | self.markDirty(shdr_index, phdr_index); | 899 | self.markDirty(shdr_index, phdr_index); |
| 871 | } | 900 | } |
| 872 | | 901 | |
| | 902 | fn growSegment(self: *Elf, shndx: u16, needed_size: u64) !void { |
| | 903 | const phdr_index = self.phdr_to_shdr_table.get(shndx).?; |
| | 904 | const phdr = &self.phdrs.items[phdr_index]; |
| | 905 | const increased_size = padToIdeal(needed_size); |
| | 906 | const end_addr = phdr.p_vaddr + phdr.p_memsz; |
| | 907 | const old_aligned_end = phdr.p_vaddr + mem.alignForward(u64, phdr.p_memsz, phdr.p_align); |
| | 908 | const new_aligned_end = phdr.p_vaddr + mem.alignForward(u64, increased_size, phdr.p_align); |
| | 909 | const diff = new_aligned_end - old_aligned_end; |
| | 910 | log.debug("growing phdr({d}) in memory by {x}", .{ phdr_index, diff }); |
| | 911 | |
| | 912 | // Update symbols and atoms. |
| | 913 | var files = std.ArrayList(File.Index).init(self.base.allocator); |
| | 914 | defer files.deinit(); |
| | 915 | try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); |
| | 916 | |
| | 917 | if (self.zig_module_index) |index| files.appendAssumeCapacity(index); |
| | 918 | files.appendSliceAssumeCapacity(self.objects.items); |
| | 919 | |
| | 920 | for (files.items) |index| { |
| | 921 | const file_ptr = self.file(index).?; |
| | 922 | |
| | 923 | for (file_ptr.locals()) |sym_index| { |
| | 924 | const sym = self.symbol(sym_index); |
| | 925 | const atom_ptr = sym.atom(self) orelse continue; |
| | 926 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| | 927 | if (sym.value >= end_addr) sym.value += diff; |
| | 928 | } |
| | 929 | |
| | 930 | for (file_ptr.globals()) |sym_index| { |
| | 931 | const sym = self.symbol(sym_index); |
| | 932 | if (sym.file_index != index) continue; |
| | 933 | const atom_ptr = sym.atom(self) orelse continue; |
| | 934 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| | 935 | if (sym.value >= end_addr) sym.value += diff; |
| | 936 | } |
| | 937 | |
| | 938 | for (file_ptr.atoms()) |atom_index| { |
| | 939 | const atom_ptr = self.atom(atom_index) orelse continue; |
| | 940 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| | 941 | if (atom_ptr.value >= end_addr) atom_ptr.value += diff; |
| | 942 | } |
| | 943 | } |
| | 944 | |
| | 945 | // Finally, update section headers. |
| | 946 | for (self.shdrs.items, 0..) |*other_shdr, other_shndx| { |
| | 947 | if (other_shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| | 948 | if (other_shndx == shndx) continue; |
| | 949 | const other_phdr_index = self.phdr_to_shdr_table.get(@intCast(other_shndx)) orelse continue; |
| | 950 | const other_phdr = &self.phdrs.items[other_phdr_index]; |
| | 951 | if (other_phdr.p_vaddr < end_addr) continue; |
| | 952 | other_shdr.sh_addr += diff; |
| | 953 | other_phdr.p_vaddr += diff; |
| | 954 | other_phdr.p_paddr += diff; |
| | 955 | } |
| | 956 | } |
| | 957 | |
| 873 | pub fn growNonAllocSection( | 958 | pub fn growNonAllocSection( |
| 874 | self: *Elf, | 959 | self: *Elf, |
| 875 | shdr_index: u16, | 960 | shdr_index: u16, |
| ... | @@ -1143,7 +1228,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1143,7 +1228,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1143 | if (self.zig_module_index) |index| { | 1228 | if (self.zig_module_index) |index| { |
| 1144 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { | 1229 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { |
| 1145 | const atom_ptr = self.atom(atom_index).?; | 1230 | const atom_ptr = self.atom(atom_index).?; |
| 1146 | if (!atom_ptr.alive) continue; | 1231 | if (!atom_ptr.flags.alive) continue; |
| 1147 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; | 1232 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1148 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; | 1233 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1149 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 1234 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| ... | @@ -1157,6 +1242,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1157,6 +1242,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1157 | } | 1242 | } |
| 1158 | try self.writeObjects(); | 1243 | try self.writeObjects(); |
| 1159 | | 1244 | |
| | 1245 | if (self.got_dirty) { |
| | 1246 | const shdr = &self.shdrs.items[self.got_section_index.?]; |
| | 1247 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self)); |
| | 1248 | defer buffer.deinit(); |
| | 1249 | try self.got.writeAllEntries(self, buffer.writer()); |
| | 1250 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| | 1251 | self.got_dirty = false; |
| | 1252 | } |
| | 1253 | |
| 1160 | // Look for entry address in objects if not set by the incremental compiler. | 1254 | // Look for entry address in objects if not set by the incremental compiler. |
| 1161 | if (self.entry_addr == null) { | 1255 | if (self.entry_addr == null) { |
| 1162 | const entry: ?[]const u8 = entry: { | 1256 | const entry: ?[]const u8 = entry: { |
| ... | @@ -1537,7 +1631,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { | ... | @@ -1537,7 +1631,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { |
| 1537 | for (try object.comdatGroupMembers(cg.shndx)) |shndx| { | 1631 | for (try object.comdatGroupMembers(cg.shndx)) |shndx| { |
| 1538 | const atom_index = object.atoms.items[shndx]; | 1632 | const atom_index = object.atoms.items[shndx]; |
| 1539 | if (self.atom(atom_index)) |atom_ptr| { | 1633 | if (self.atom(atom_index)) |atom_ptr| { |
| 1540 | atom_ptr.alive = false; | 1634 | atom_ptr.flags.alive = false; |
| 1541 | // atom_ptr.markFdesDead(self); | 1635 | // atom_ptr.markFdesDead(self); |
| 1542 | } | 1636 | } |
| 1543 | } | 1637 | } |
| ... | @@ -1645,25 +1739,26 @@ fn scanRelocs(self: *Elf) !void { | ... | @@ -1645,25 +1739,26 @@ fn scanRelocs(self: *Elf) !void { |
| 1645 | fn allocateObjects(self: *Elf) !void { | 1739 | fn allocateObjects(self: *Elf) !void { |
| 1646 | for (self.objects.items) |index| { | 1740 | for (self.objects.items) |index| { |
| 1647 | const object = self.file(index).?.object; | 1741 | const object = self.file(index).?.object; |
| | 1742 | |
| 1648 | for (object.atoms.items) |atom_index| { | 1743 | for (object.atoms.items) |atom_index| { |
| 1649 | const atom_ptr = self.atom(atom_index) orelse continue; | 1744 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1650 | if (!atom_ptr.alive) continue; | 1745 | if (!atom_ptr.flags.alive or atom_ptr.flags.allocated) continue; |
| 1651 | try atom_ptr.allocate(self); | 1746 | try atom_ptr.allocate(self); |
| 1652 | } | 1747 | } |
| 1653 | | 1748 | |
| 1654 | for (object.locals()) |local_index| { | 1749 | for (object.locals()) |local_index| { |
| 1655 | const local = self.symbol(local_index); | 1750 | const local = self.symbol(local_index); |
| 1656 | const atom_ptr = local.atom(self) orelse continue; | 1751 | const atom_ptr = local.atom(self) orelse continue; |
| 1657 | if (!atom_ptr.alive) continue; | 1752 | if (!atom_ptr.flags.alive) continue; |
| 1658 | local.value += atom_ptr.value; | 1753 | local.value = local.elfSym(self).st_value + atom_ptr.value; |
| 1659 | } | 1754 | } |
| 1660 | | 1755 | |
| 1661 | for (object.globals()) |global_index| { | 1756 | for (object.globals()) |global_index| { |
| 1662 | const global = self.symbol(global_index); | 1757 | const global = self.symbol(global_index); |
| 1663 | const atom_ptr = global.atom(self) orelse continue; | 1758 | const atom_ptr = global.atom(self) orelse continue; |
| 1664 | if (!atom_ptr.alive) continue; | 1759 | if (!atom_ptr.flags.alive) continue; |
| 1665 | if (global.file_index == index) { | 1760 | if (global.file_index == index) { |
| 1666 | global.value += atom_ptr.value; | 1761 | global.value = global.elfSym(self).st_value + atom_ptr.value; |
| 1667 | } | 1762 | } |
| 1668 | } | 1763 | } |
| 1669 | } | 1764 | } |
| ... | @@ -1676,7 +1771,7 @@ fn writeObjects(self: *Elf) !void { | ... | @@ -1676,7 +1771,7 @@ fn writeObjects(self: *Elf) !void { |
| 1676 | const object = self.file(index).?.object; | 1771 | const object = self.file(index).?.object; |
| 1677 | for (object.atoms.items) |atom_index| { | 1772 | for (object.atoms.items) |atom_index| { |
| 1678 | const atom_ptr = self.atom(atom_index) orelse continue; | 1773 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1679 | if (!atom_ptr.alive) continue; | 1774 | if (!atom_ptr.flags.alive) continue; |
| 1680 | | 1775 | |
| 1681 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; | 1776 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1682 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | 1777 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| ... | @@ -2650,7 +2745,7 @@ fn updateDeclCode( | ... | @@ -2650,7 +2745,7 @@ fn updateDeclCode( |
| 2650 | atom_ptr.output_section_index = shdr_index; | 2745 | atom_ptr.output_section_index = shdr_index; |
| 2651 | | 2746 | |
| 2652 | sym.name_offset = try self.strtab.insert(gpa, decl_name); | 2747 | sym.name_offset = try self.strtab.insert(gpa, decl_name); |
| 2653 | atom_ptr.alive = true; | 2748 | atom_ptr.flags.alive = true; |
| 2654 | atom_ptr.name_offset = sym.name_offset; | 2749 | atom_ptr.name_offset = sym.name_offset; |
| 2655 | esym.st_name = sym.name_offset; | 2750 | esym.st_name = sym.name_offset; |
| 2656 | esym.st_info |= stt_bits; | 2751 | esym.st_info |= stt_bits; |
| ... | @@ -2681,11 +2776,6 @@ fn updateDeclCode( | ... | @@ -2681,11 +2776,6 @@ fn updateDeclCode( |
| 2681 | } else { | 2776 | } else { |
| 2682 | try atom_ptr.allocate(self); | 2777 | try atom_ptr.allocate(self); |
| 2683 | errdefer self.freeDeclMetadata(sym_index); | 2778 | errdefer self.freeDeclMetadata(sym_index); |
| 2684 | log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{ | | |
| 2685 | decl_name, | | |
| 2686 | atom_ptr.value, | | |
| 2687 | atom_ptr.value + atom_ptr.size, | | |
| 2688 | }); | | |
| 2689 | | 2779 | |
| 2690 | sym.value = atom_ptr.value; | 2780 | sym.value = atom_ptr.value; |
| 2691 | esym.st_value = atom_ptr.value; | 2781 | esym.st_value = atom_ptr.value; |
| ... | @@ -2873,7 +2963,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2873,7 +2963,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2873 | defer gpa.free(name); | 2963 | defer gpa.free(name); |
| 2874 | break :blk try self.strtab.insert(gpa, name); | 2964 | break :blk try self.strtab.insert(gpa, name); |
| 2875 | }; | 2965 | }; |
| 2876 | const name = self.strtab.get(name_str_index).?; | | |
| 2877 | | 2966 | |
| 2878 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| | 2967 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 2879 | mod.declPtr(owner_decl).srcLoc(mod) | 2968 | mod.declPtr(owner_decl).srcLoc(mod) |
| ... | @@ -2913,7 +3002,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2913,7 +3002,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2913 | local_esym.st_info |= elf.STT_OBJECT; | 3002 | local_esym.st_info |= elf.STT_OBJECT; |
| 2914 | local_esym.st_size = code.len; | 3003 | local_esym.st_size = code.len; |
| 2915 | const atom_ptr = local_sym.atom(self).?; | 3004 | const atom_ptr = local_sym.atom(self).?; |
| 2916 | atom_ptr.alive = true; | 3005 | atom_ptr.flags.alive = true; |
| 2917 | atom_ptr.name_offset = name_str_index; | 3006 | atom_ptr.name_offset = name_str_index; |
| 2918 | atom_ptr.alignment = required_alignment; | 3007 | atom_ptr.alignment = required_alignment; |
| 2919 | atom_ptr.size = code.len; | 3008 | atom_ptr.size = code.len; |
| ... | @@ -2922,12 +3011,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2922,12 +3011,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2922 | try atom_ptr.allocate(self); | 3011 | try atom_ptr.allocate(self); |
| 2923 | errdefer self.freeDeclMetadata(symbol_index); | 3012 | errdefer self.freeDeclMetadata(symbol_index); |
| 2924 | | 3013 | |
| 2925 | log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{ | | |
| 2926 | name, | | |
| 2927 | atom_ptr.value, | | |
| 2928 | atom_ptr.value + atom_ptr.size, | | |
| 2929 | }); | | |
| 2930 | | | |
| 2931 | local_sym.value = atom_ptr.value; | 3014 | local_sym.value = atom_ptr.value; |
| 2932 | local_esym.st_value = atom_ptr.value; | 3015 | local_esym.st_value = atom_ptr.value; |
| 2933 | | 3016 | |
| ... | @@ -2961,7 +3044,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2961,7 +3044,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2961 | defer gpa.free(name); | 3044 | defer gpa.free(name); |
| 2962 | break :blk try self.strtab.insert(gpa, name); | 3045 | break :blk try self.strtab.insert(gpa, name); |
| 2963 | }; | 3046 | }; |
| 2964 | const name = self.strtab.get(name_str_index).?; | | |
| 2965 | | 3047 | |
| 2966 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 3048 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2967 | const sym_index = try zig_module.addAtom(self); | 3049 | const sym_index = try zig_module.addAtom(self); |
| ... | @@ -2992,7 +3074,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2992,7 +3074,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2992 | local_esym.st_info |= elf.STT_OBJECT; | 3074 | local_esym.st_info |= elf.STT_OBJECT; |
| 2993 | local_esym.st_size = code.len; | 3075 | local_esym.st_size = code.len; |
| 2994 | const atom_ptr = local_sym.atom(self).?; | 3076 | const atom_ptr = local_sym.atom(self).?; |
| 2995 | atom_ptr.alive = true; | 3077 | atom_ptr.flags.alive = true; |
| 2996 | atom_ptr.name_offset = name_str_index; | 3078 | atom_ptr.name_offset = name_str_index; |
| 2997 | atom_ptr.alignment = required_alignment; | 3079 | atom_ptr.alignment = required_alignment; |
| 2998 | atom_ptr.size = code.len; | 3080 | atom_ptr.size = code.len; |
| ... | @@ -3001,8 +3083,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -3001,8 +3083,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 3001 | try atom_ptr.allocate(self); | 3083 | try atom_ptr.allocate(self); |
| 3002 | errdefer self.freeDeclMetadata(sym_index); | 3084 | errdefer self.freeDeclMetadata(sym_index); |
| 3003 | | 3085 | |
| 3004 | log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{ name, atom_ptr.value, atom_ptr.value + atom_ptr.size }); | | |
| 3005 | | | |
| 3006 | local_sym.value = atom_ptr.value; | 3086 | local_sym.value = atom_ptr.value; |
| 3007 | local_esym.st_value = atom_ptr.value; | 3087 | local_esym.st_value = atom_ptr.value; |
| 3008 | | 3088 | |
| ... | @@ -3931,6 +4011,50 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO | ... | @@ -3931,6 +4011,50 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO |
| 3931 | return &self.comdat_groups_owners.items[index]; | 4011 | return &self.comdat_groups_owners.items[index]; |
| 3932 | } | 4012 | } |
| 3933 | | 4013 | |
| | 4014 | const ErrorWithNotes = struct { |
| | 4015 | /// Allocated index in misc_errors array. |
| | 4016 | index: usize, |
| | 4017 | |
| | 4018 | /// Next available note slot. |
| | 4019 | note_slot: usize = 0, |
| | 4020 | |
| | 4021 | pub fn addMsg( |
| | 4022 | err: ErrorWithNotes, |
| | 4023 | elf_file: *Elf, |
| | 4024 | comptime format: []const u8, |
| | 4025 | args: anytype, |
| | 4026 | ) error{OutOfMemory}!void { |
| | 4027 | const gpa = elf_file.base.allocator; |
| | 4028 | const err_msg = &elf_file.misc_errors.items[err.index]; |
| | 4029 | err_msg.msg = try std.fmt.allocPrint(gpa, format, args); |
| | 4030 | } |
| | 4031 | |
| | 4032 | pub fn addNote( |
| | 4033 | err: *ErrorWithNotes, |
| | 4034 | elf_file: *Elf, |
| | 4035 | comptime format: []const u8, |
| | 4036 | args: anytype, |
| | 4037 | ) error{OutOfMemory}!void { |
| | 4038 | const gpa = elf_file.base.allocator; |
| | 4039 | const err_msg = &elf_file.misc_errors.items[err.index]; |
| | 4040 | assert(err.note_slot < err_msg.notes.len); |
| | 4041 | err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) }; |
| | 4042 | err.note_slot += 1; |
| | 4043 | } |
| | 4044 | }; |
| | 4045 | |
| | 4046 | fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { |
| | 4047 | try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1); |
| | 4048 | return self.addErrorWithNotesAssumeCapacity(note_count); |
| | 4049 | } |
| | 4050 | |
| | 4051 | fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { |
| | 4052 | const index = self.misc_errors.items.len; |
| | 4053 | const err = self.misc_errors.addOneAssumeCapacity(); |
| | 4054 | err.* = .{ .msg = undefined, .notes = try self.base.allocator.alloc(link.File.ErrorMsg, note_count) }; |
| | 4055 | return .{ .index = index }; |
| | 4056 | } |
| | 4057 | |
| 3934 | fn reportUndefined(self: *Elf, undefs: anytype) !void { | 4058 | fn reportUndefined(self: *Elf, undefs: anytype) !void { |
| 3935 | const gpa = self.base.allocator; | 4059 | const gpa = self.base.allocator; |
| 3936 | const max_notes = 4; | 4060 | const max_notes = 4; |
| ... | @@ -3941,33 +4065,22 @@ fn reportUndefined(self: *Elf, undefs: anytype) !void { | ... | @@ -3941,33 +4065,22 @@ fn reportUndefined(self: *Elf, undefs: anytype) !void { |
| 3941 | while (it.next()) |entry| { | 4065 | while (it.next()) |entry| { |
| 3942 | const undef_index = entry.key_ptr.*; | 4066 | const undef_index = entry.key_ptr.*; |
| 3943 | const atoms = entry.value_ptr.*.items; | 4067 | const atoms = entry.value_ptr.*.items; |
| 3944 | const nnotes = @min(atoms.len, max_notes); | 4068 | const natoms = @min(atoms.len, max_notes); |
| | 4069 | const nnotes = natoms + @intFromBool(atoms.len > max_notes); |
| 3945 | | 4070 | |
| 3946 | var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1); | 4071 | var err = try self.addErrorWithNotesAssumeCapacity(nnotes); |
| 3947 | defer notes.deinit(); | 4072 | try err.addMsg(self, "undefined symbol: {s}", .{self.symbol(undef_index).name(self)}); |
| 3948 | | 4073 | |
| 3949 | for (atoms[0..nnotes]) |atom_index| { | 4074 | for (atoms[0..natoms]) |atom_index| { |
| 3950 | const atom_ptr = self.atom(atom_index).?; | 4075 | const atom_ptr = self.atom(atom_index).?; |
| 3951 | const file_ptr = self.file(atom_ptr.file_index).?; | 4076 | const file_ptr = self.file(atom_ptr.file_index).?; |
| 3952 | const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{ | 4077 | try err.addNote(self, "referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); |
| 3953 | file_ptr.fmtPath(), | | |
| 3954 | atom_ptr.name(self), | | |
| 3955 | }); | | |
| 3956 | notes.appendAssumeCapacity(.{ .msg = note }); | | |
| 3957 | } | 4078 | } |
| 3958 | | 4079 | |
| 3959 | if (atoms.len > max_notes) { | 4080 | if (atoms.len > max_notes) { |
| 3960 | const remaining = atoms.len - max_notes; | 4081 | const remaining = atoms.len - max_notes; |
| 3961 | const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining}); | 4082 | try err.addNote(self, "referenced {d} more times", .{remaining}); |
| 3962 | notes.appendAssumeCapacity(.{ .msg = note }); | | |
| 3963 | } | 4083 | } |
| 3964 | | | |
| 3965 | var err_msg = link.File.ErrorMsg{ | | |
| 3966 | .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{self.symbol(undef_index).name(self)}), | | |
| 3967 | }; | | |
| 3968 | err_msg.notes = try notes.toOwnedSlice(); | | |
| 3969 | | | |
| 3970 | self.misc_errors.appendAssumeCapacity(err_msg); | | |
| 3971 | } | 4084 | } |
| 3972 | } | 4085 | } |
| 3973 | | 4086 | |
| ... | @@ -4003,15 +4116,9 @@ fn reportParseError( | ... | @@ -4003,15 +4116,9 @@ fn reportParseError( |
| 4003 | comptime format: []const u8, | 4116 | comptime format: []const u8, |
| 4004 | args: anytype, | 4117 | args: anytype, |
| 4005 | ) error{OutOfMemory}!void { | 4118 | ) error{OutOfMemory}!void { |
| 4006 | const gpa = self.base.allocator; | 4119 | var err = try self.addErrorWithNotes(1); |
| 4007 | try self.misc_errors.ensureUnusedCapacity(gpa, 1); | 4120 | try err.addMsg(self, format, args); |
| 4008 | var notes = try gpa.alloc(link.File.ErrorMsg, 1); | 4121 | try err.addNote(self, "while parsing {s}", .{path}); |
| 4009 | errdefer gpa.free(notes); | | |
| 4010 | notes[0] = .{ .msg = try std.fmt.allocPrint(gpa, "while parsing {s}", .{path}) }; | | |
| 4011 | self.misc_errors.appendAssumeCapacity(.{ | | |
| 4012 | .msg = try std.fmt.allocPrint(gpa, format, args), | | |
| 4013 | .notes = notes, | | |
| 4014 | }); | | |
| 4015 | } | 4122 | } |
| 4016 | | 4123 | |
| 4017 | fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) { | 4124 | fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) { |