| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | base: link.File, |
| 2 | |
| 2 | 3 | dwarf: ?Dwarf = null, |
| 3 | 4 | |
| 4 | 5 | ptr_width: PtrWidth, |
| ... | ... | @@ -103,6 +104,7 @@ phdr_table_dirty: bool = false, |
| 103 | 104 | shdr_table_dirty: bool = false, |
| 104 | 105 | shstrtab_dirty: bool = false, |
| 105 | 106 | strtab_dirty: bool = false, |
| 107 | got_dirty: bool = false, |
| 106 | 108 | |
| 107 | 109 | debug_strtab_dirty: bool = false, |
| 108 | 110 | debug_abbrev_section_dirty: bool = false, |
| ... | ... | @@ -411,21 +413,31 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 411 | 413 | const AllocateSegmentOpts = struct { |
| 412 | 414 | size: u64, |
| 413 | 415 | alignment: u64, |
| 414 | | addr: ?u64 = null, // TODO find free VM space |
| 416 | addr: ?u64 = null, |
| 415 | 417 | flags: u32 = elf.PF_R, |
| 416 | 418 | }; |
| 417 | 419 | |
| 418 | 420 | pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 { |
| 421 | const gpa = self.base.allocator; |
| 419 | 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 | 424 | const off = self.findFreeSpace(opts.size, opts.alignment); |
| 422 | | // Memory is always allocated in sequence. |
| 423 | | // TODO is this correct? Or should we implement something similar to `findFreeSpace`? |
| 424 | | // How would that impact HCS? |
| 425 | // Currently, we automatically allocate memory in sequence by finding the largest |
| 426 | // allocated virtual address and going from there. |
| 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 | 429 | const addr = opts.addr orelse blk: { |
| 426 | | assert(self.phdr_table_load_index != null); |
| 427 | | const phdr = &self.phdrs.items[index - 1]; |
| 428 | | break :blk mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, opts.alignment); |
| 430 | const reserved_capacity = self.calcImageBase() * 4; |
| 431 | // Calculate largest VM address |
| 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 | 442 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 431 | 443 | index, |
| ... | ... | @@ -530,6 +542,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 530 | 542 | .p64 => false, |
| 531 | 543 | }; |
| 532 | 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 | 547 | const image_base = self.calcImageBase(); |
| 534 | 548 | |
| 535 | 549 | if (self.phdr_table_index == null) { |
| ... | ... | @@ -577,13 +591,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 577 | 591 | } |
| 578 | 592 | |
| 579 | 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. |
| 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; |
| 594 | const addr: u64 = if (large_addrspace) 0x4000000 else 0x8000; |
| 584 | 595 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 585 | 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 | 598 | self.phdr_got_index = try self.allocateSegment(.{ |
| 588 | 599 | .addr = addr, |
| 589 | 600 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| ... | ... | @@ -593,10 +604,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 593 | 604 | } |
| 594 | 605 | |
| 595 | 606 | if (self.phdr_load_ro_index == null) { |
| 596 | | // TODO Same as for GOT |
| 597 | | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; |
| 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); |
| 607 | const addr: u64 = if (large_addrspace) 0xc000000 else 0xa000; |
| 608 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 600 | 609 | self.phdr_load_ro_index = try self.allocateSegment(.{ |
| 601 | 610 | .addr = addr, |
| 602 | 611 | .size = 1024, |
| ... | ... | @@ -606,10 +615,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 606 | 615 | } |
| 607 | 616 | |
| 608 | 617 | if (self.phdr_load_rw_index == null) { |
| 609 | | // TODO Same as for GOT |
| 610 | | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; |
| 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); |
| 618 | const addr: u64 = if (large_addrspace) 0x10000000 else 0xc000; |
| 619 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 613 | 620 | self.phdr_load_rw_index = try self.allocateSegment(.{ |
| 614 | 621 | .addr = addr, |
| 615 | 622 | .size = 1024, |
| ... | ... | @@ -619,9 +626,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 619 | 626 | } |
| 620 | 627 | |
| 621 | 628 | if (self.phdr_load_zerofill_index == null) { |
| 622 | | // TODO Same as for GOT |
| 623 | | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; |
| 624 | | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 629 | const addr: u64 = if (large_addrspace) 0x14000000 else 0xf000; |
| 630 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 625 | 631 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ |
| 626 | 632 | .addr = addr, |
| 627 | 633 | .size = 0, |
| ... | ... | @@ -803,7 +809,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 803 | 809 | } |
| 804 | 810 | |
| 805 | 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 | 813 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 808 | 814 | self.files.set(index, .{ .zig_module = .{ |
| 809 | 815 | .index = index, |
| ... | ... | @@ -858,7 +864,30 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 858 | 864 | } |
| 859 | 865 | |
| 860 | 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 | 892 | shdr.sh_size = needed_size; |
| 864 | 893 | phdr.p_memsz = needed_size; |
| ... | ... | @@ -870,6 +899,62 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 870 | 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 | 958 | pub fn growNonAllocSection( |
| 874 | 959 | self: *Elf, |
| 875 | 960 | shdr_index: u16, |
| ... | ... | @@ -1143,7 +1228,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1143 | 1228 | if (self.zig_module_index) |index| { |
| 1144 | 1229 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { |
| 1145 | 1230 | const atom_ptr = self.atom(atom_index).?; |
| 1146 | | if (!atom_ptr.alive) continue; |
| 1231 | if (!atom_ptr.flags.alive) continue; |
| 1147 | 1232 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1148 | 1233 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1149 | 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 | 1242 | } |
| 1158 | 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 | 1254 | // Look for entry address in objects if not set by the incremental compiler. |
| 1161 | 1255 | if (self.entry_addr == null) { |
| 1162 | 1256 | const entry: ?[]const u8 = entry: { |
| ... | ... | @@ -1537,7 +1631,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { |
| 1537 | 1631 | for (try object.comdatGroupMembers(cg.shndx)) |shndx| { |
| 1538 | 1632 | const atom_index = object.atoms.items[shndx]; |
| 1539 | 1633 | if (self.atom(atom_index)) |atom_ptr| { |
| 1540 | | atom_ptr.alive = false; |
| 1634 | atom_ptr.flags.alive = false; |
| 1541 | 1635 | // atom_ptr.markFdesDead(self); |
| 1542 | 1636 | } |
| 1543 | 1637 | } |
| ... | ... | @@ -1645,25 +1739,26 @@ fn scanRelocs(self: *Elf) !void { |
| 1645 | 1739 | fn allocateObjects(self: *Elf) !void { |
| 1646 | 1740 | for (self.objects.items) |index| { |
| 1647 | 1741 | const object = self.file(index).?.object; |
| 1742 | |
| 1648 | 1743 | for (object.atoms.items) |atom_index| { |
| 1649 | 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 | 1746 | try atom_ptr.allocate(self); |
| 1652 | 1747 | } |
| 1653 | 1748 | |
| 1654 | 1749 | for (object.locals()) |local_index| { |
| 1655 | 1750 | const local = self.symbol(local_index); |
| 1656 | 1751 | const atom_ptr = local.atom(self) orelse continue; |
| 1657 | | if (!atom_ptr.alive) continue; |
| 1658 | | local.value += atom_ptr.value; |
| 1752 | if (!atom_ptr.flags.alive) continue; |
| 1753 | local.value = local.elfSym(self).st_value + atom_ptr.value; |
| 1659 | 1754 | } |
| 1660 | 1755 | |
| 1661 | 1756 | for (object.globals()) |global_index| { |
| 1662 | 1757 | const global = self.symbol(global_index); |
| 1663 | 1758 | const atom_ptr = global.atom(self) orelse continue; |
| 1664 | | if (!atom_ptr.alive) continue; |
| 1759 | if (!atom_ptr.flags.alive) continue; |
| 1665 | 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 | 1771 | const object = self.file(index).?.object; |
| 1677 | 1772 | for (object.atoms.items) |atom_index| { |
| 1678 | 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 | 1776 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1682 | 1777 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| ... | ... | @@ -2650,7 +2745,7 @@ fn updateDeclCode( |
| 2650 | 2745 | atom_ptr.output_section_index = shdr_index; |
| 2651 | 2746 | |
| 2652 | 2747 | sym.name_offset = try self.strtab.insert(gpa, decl_name); |
| 2653 | | atom_ptr.alive = true; |
| 2748 | atom_ptr.flags.alive = true; |
| 2654 | 2749 | atom_ptr.name_offset = sym.name_offset; |
| 2655 | 2750 | esym.st_name = sym.name_offset; |
| 2656 | 2751 | esym.st_info |= stt_bits; |
| ... | ... | @@ -2681,11 +2776,6 @@ fn updateDeclCode( |
| 2681 | 2776 | } else { |
| 2682 | 2777 | try atom_ptr.allocate(self); |
| 2683 | 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 | 2780 | sym.value = atom_ptr.value; |
| 2691 | 2781 | esym.st_value = atom_ptr.value; |
| ... | ... | @@ -2873,7 +2963,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2873 | 2963 | defer gpa.free(name); |
| 2874 | 2964 | break :blk try self.strtab.insert(gpa, name); |
| 2875 | 2965 | }; |
| 2876 | | const name = self.strtab.get(name_str_index).?; |
| 2877 | 2966 | |
| 2878 | 2967 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 2879 | 2968 | mod.declPtr(owner_decl).srcLoc(mod) |
| ... | ... | @@ -2913,7 +3002,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2913 | 3002 | local_esym.st_info |= elf.STT_OBJECT; |
| 2914 | 3003 | local_esym.st_size = code.len; |
| 2915 | 3004 | const atom_ptr = local_sym.atom(self).?; |
| 2916 | | atom_ptr.alive = true; |
| 3005 | atom_ptr.flags.alive = true; |
| 2917 | 3006 | atom_ptr.name_offset = name_str_index; |
| 2918 | 3007 | atom_ptr.alignment = required_alignment; |
| 2919 | 3008 | atom_ptr.size = code.len; |
| ... | ... | @@ -2922,12 +3011,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2922 | 3011 | try atom_ptr.allocate(self); |
| 2923 | 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 | 3014 | local_sym.value = atom_ptr.value; |
| 2932 | 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 | 3044 | defer gpa.free(name); |
| 2962 | 3045 | break :blk try self.strtab.insert(gpa, name); |
| 2963 | 3046 | }; |
| 2964 | | const name = self.strtab.get(name_str_index).?; |
| 2965 | 3047 | |
| 2966 | 3048 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2967 | 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 | 3074 | local_esym.st_info |= elf.STT_OBJECT; |
| 2993 | 3075 | local_esym.st_size = code.len; |
| 2994 | 3076 | const atom_ptr = local_sym.atom(self).?; |
| 2995 | | atom_ptr.alive = true; |
| 3077 | atom_ptr.flags.alive = true; |
| 2996 | 3078 | atom_ptr.name_offset = name_str_index; |
| 2997 | 3079 | atom_ptr.alignment = required_alignment; |
| 2998 | 3080 | atom_ptr.size = code.len; |
| ... | ... | @@ -3001,8 +3083,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 3001 | 3083 | try atom_ptr.allocate(self); |
| 3002 | 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 | 3086 | local_sym.value = atom_ptr.value; |
| 3007 | 3087 | local_esym.st_value = atom_ptr.value; |
| 3008 | 3088 | |
| ... | ... | @@ -3931,6 +4011,50 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO |
| 3931 | 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 | 4058 | fn reportUndefined(self: *Elf, undefs: anytype) !void { |
| 3935 | 4059 | const gpa = self.base.allocator; |
| 3936 | 4060 | const max_notes = 4; |
| ... | ... | @@ -3941,33 +4065,22 @@ fn reportUndefined(self: *Elf, undefs: anytype) !void { |
| 3941 | 4065 | while (it.next()) |entry| { |
| 3942 | 4066 | const undef_index = entry.key_ptr.*; |
| 3943 | 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); |
| 3947 | | defer notes.deinit(); |
| 4071 | var err = try self.addErrorWithNotesAssumeCapacity(nnotes); |
| 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 | 4075 | const atom_ptr = self.atom(atom_index).?; |
| 3951 | 4076 | const file_ptr = self.file(atom_ptr.file_index).?; |
| 3952 | | const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{ |
| 3953 | | file_ptr.fmtPath(), |
| 3954 | | atom_ptr.name(self), |
| 3955 | | }); |
| 3956 | | notes.appendAssumeCapacity(.{ .msg = note }); |
| 4077 | try err.addNote(self, "referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); |
| 3957 | 4078 | } |
| 3958 | 4079 | |
| 3959 | 4080 | if (atoms.len > max_notes) { |
| 3960 | 4081 | const remaining = atoms.len - max_notes; |
| 3961 | | const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining}); |
| 3962 | | notes.appendAssumeCapacity(.{ .msg = note }); |
| 4082 | try err.addNote(self, "referenced {d} more times", .{remaining}); |
| 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 | 4116 | comptime format: []const u8, |
| 4004 | 4117 | args: anytype, |
| 4005 | 4118 | ) error{OutOfMemory}!void { |
| 4006 | | const gpa = self.base.allocator; |
| 4007 | | try self.misc_errors.ensureUnusedCapacity(gpa, 1); |
| 4008 | | var notes = try gpa.alloc(link.File.ErrorMsg, 1); |
| 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 | | }); |
| 4119 | var err = try self.addErrorWithNotes(1); |
| 4120 | try err.addMsg(self, format, args); |
| 4121 | try err.addNote(self, "while parsing {s}", .{path}); |
| 4015 | 4122 | } |
| 4016 | 4123 | |
| 4017 | 4124 | fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) { |