| ... | ... | @@ -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,7 +413,6 @@ 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 |
| 415 | 416 | flags: u32 = elf.PF_R, |
| 416 | 417 | }; |
| 417 | 418 | |
| ... | ... | @@ -422,7 +423,7 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory} |
| 422 | 423 | // Memory is always allocated in sequence. |
| 423 | 424 | // TODO is this correct? Or should we implement something similar to `findFreeSpace`? |
| 424 | 425 | // How would that impact HCS? |
| 425 | | const addr = opts.addr orelse blk: { |
| 426 | const addr = blk: { |
| 426 | 427 | assert(self.phdr_table_load_index != null); |
| 427 | 428 | const phdr = &self.phdrs.items[index - 1]; |
| 428 | 429 | break :blk mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, opts.alignment); |
| ... | ... | @@ -568,7 +569,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 568 | 569 | |
| 569 | 570 | if (self.phdr_load_re_index == null) { |
| 570 | 571 | self.phdr_load_re_index = try self.allocateSegment(.{ |
| 571 | | .addr = self.defaultEntryAddress(), |
| 572 | 572 | .size = self.base.options.program_code_size_hint, |
| 573 | 573 | .alignment = self.page_size, |
| 574 | 574 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| ... | ... | @@ -577,15 +577,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 577 | 577 | } |
| 578 | 578 | |
| 579 | 579 | 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; |
| 584 | 580 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 585 | 581 | // page align. |
| 586 | 582 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 587 | 583 | self.phdr_got_index = try self.allocateSegment(.{ |
| 588 | | .addr = addr, |
| 589 | 584 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 590 | 585 | .alignment = alignment, |
| 591 | 586 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -593,12 +588,9 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 593 | 588 | } |
| 594 | 589 | |
| 595 | 590 | 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 | 591 | // Same reason as for GOT |
| 599 | 592 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 600 | 593 | self.phdr_load_ro_index = try self.allocateSegment(.{ |
| 601 | | .addr = addr, |
| 602 | 594 | .size = 1024, |
| 603 | 595 | .alignment = alignment, |
| 604 | 596 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -606,12 +598,9 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 606 | 598 | } |
| 607 | 599 | |
| 608 | 600 | 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 | 601 | // Same reason as for GOT |
| 612 | 602 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 613 | 603 | self.phdr_load_rw_index = try self.allocateSegment(.{ |
| 614 | | .addr = addr, |
| 615 | 604 | .size = 1024, |
| 616 | 605 | .alignment = alignment, |
| 617 | 606 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -619,11 +608,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 619 | 608 | } |
| 620 | 609 | |
| 621 | 610 | 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 | 611 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 625 | 612 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ |
| 626 | | .addr = addr, |
| 627 | 613 | .size = 0, |
| 628 | 614 | .alignment = alignment, |
| 629 | 615 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -858,7 +844,19 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 858 | 844 | } |
| 859 | 845 | |
| 860 | 846 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| 861 | | assert(needed_size <= mem_capacity); // TODO grow section in virtual memory |
| 847 | if (needed_size > mem_capacity) { |
| 848 | // We are exceeding our allocated VM capacity so we need to shift everything in memory |
| 849 | // and grow. |
| 850 | { |
| 851 | const dirty_addr = phdr.p_vaddr + phdr.p_memsz; |
| 852 | self.got_dirty = for (self.got.entries.items) |entry| { |
| 853 | if (self.symbol(entry.symbol_index).value >= dirty_addr) break true; |
| 854 | } else false; |
| 855 | |
| 856 | // TODO mark relocs dirty |
| 857 | } |
| 858 | try self.growSegment(shdr_index, needed_size); |
| 859 | } |
| 862 | 860 | |
| 863 | 861 | shdr.sh_size = needed_size; |
| 864 | 862 | phdr.p_memsz = needed_size; |
| ... | ... | @@ -870,6 +868,61 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 870 | 868 | self.markDirty(shdr_index, phdr_index); |
| 871 | 869 | } |
| 872 | 870 | |
| 871 | fn growSegment(self: *Elf, shndx: u16, needed_size: u64) !void { |
| 872 | const phdr_index = self.phdr_to_shdr_table.get(shndx).?; |
| 873 | const phdr = &self.phdrs.items[phdr_index]; |
| 874 | const increased_size = padToIdeal(needed_size); |
| 875 | const end_addr = phdr.p_vaddr + phdr.p_memsz; |
| 876 | const old_aligned_end = phdr.p_vaddr + mem.alignForward(u64, phdr.p_memsz, phdr.p_align); |
| 877 | const new_aligned_end = phdr.p_vaddr + mem.alignForward(u64, increased_size, phdr.p_align); |
| 878 | const diff = new_aligned_end - old_aligned_end; |
| 879 | log.debug("growing phdr({d}) in memory by {x}", .{ phdr_index, diff }); |
| 880 | |
| 881 | // Update symbols and atoms. |
| 882 | var files = std.ArrayList(File.Index).init(self.base.allocator); |
| 883 | defer files.deinit(); |
| 884 | try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); |
| 885 | |
| 886 | if (self.zig_module_index) |index| files.appendAssumeCapacity(index); |
| 887 | files.appendSliceAssumeCapacity(self.objects.items); |
| 888 | |
| 889 | for (files.items) |index| { |
| 890 | const file_ptr = self.file(index).?; |
| 891 | |
| 892 | for (file_ptr.locals()) |sym_index| { |
| 893 | const sym = self.symbol(sym_index); |
| 894 | const atom_ptr = sym.atom(self) orelse continue; |
| 895 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| 896 | if (atom_ptr.value >= end_addr) sym.value += diff; |
| 897 | } |
| 898 | |
| 899 | for (file_ptr.globals()) |sym_index| { |
| 900 | const sym = self.symbol(sym_index); |
| 901 | const atom_ptr = sym.atom(self) orelse continue; |
| 902 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| 903 | if (atom_ptr.value >= end_addr) sym.value += diff; |
| 904 | } |
| 905 | |
| 906 | for (file_ptr.atoms()) |atom_index| { |
| 907 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 908 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; |
| 909 | if (atom_ptr.value >= end_addr) atom_ptr.value += diff; |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | // Finally, update section headers. |
| 914 | for (self.shdrs.items, 0..) |*other_shdr, other_shndx| { |
| 915 | if (other_shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 916 | if (other_shndx == shndx) continue; |
| 917 | const other_phdr_index = self.phdr_to_shdr_table.get(@intCast(other_shndx)) orelse continue; |
| 918 | const other_phdr = &self.phdrs.items[other_phdr_index]; |
| 919 | if (other_phdr.p_vaddr < end_addr) continue; |
| 920 | other_shdr.sh_addr += diff; |
| 921 | other_phdr.p_vaddr += diff; |
| 922 | other_phdr.p_paddr += diff; |
| 923 | } |
| 924 | } |
| 925 | |
| 873 | 926 | pub fn growNonAllocSection( |
| 874 | 927 | self: *Elf, |
| 875 | 928 | shdr_index: u16, |
| ... | ... | @@ -1133,6 +1186,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1133 | 1186 | // Scan and create missing synthetic entries such as GOT indirection. |
| 1134 | 1187 | try self.scanRelocs(); |
| 1135 | 1188 | |
| 1189 | if (build_options.enable_logging) { |
| 1190 | state_log.debug("{}", .{self.dumpState()}); |
| 1191 | } |
| 1192 | |
| 1136 | 1193 | // Allocate atoms parsed from input object files, followed by allocating |
| 1137 | 1194 | // linker-defined synthetic symbols. |
| 1138 | 1195 | try self.allocateObjects(); |
| ... | ... | @@ -1143,7 +1200,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1143 | 1200 | if (self.zig_module_index) |index| { |
| 1144 | 1201 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { |
| 1145 | 1202 | const atom_ptr = self.atom(atom_index).?; |
| 1146 | | if (!atom_ptr.alive) continue; |
| 1203 | if (!atom_ptr.flags.alive) continue; |
| 1147 | 1204 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1148 | 1205 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1149 | 1206 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| ... | ... | @@ -1157,6 +1214,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1157 | 1214 | } |
| 1158 | 1215 | try self.writeObjects(); |
| 1159 | 1216 | |
| 1217 | if (self.got_dirty) { |
| 1218 | const shdr = &self.shdrs.items[self.got_section_index.?]; |
| 1219 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self)); |
| 1220 | defer buffer.deinit(); |
| 1221 | try self.got.writeAllEntries(self, buffer.writer()); |
| 1222 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 1223 | self.got_dirty = false; |
| 1224 | } |
| 1225 | |
| 1160 | 1226 | // Look for entry address in objects if not set by the incremental compiler. |
| 1161 | 1227 | if (self.entry_addr == null) { |
| 1162 | 1228 | const entry: ?[]const u8 = entry: { |
| ... | ... | @@ -1537,7 +1603,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { |
| 1537 | 1603 | for (try object.comdatGroupMembers(cg.shndx)) |shndx| { |
| 1538 | 1604 | const atom_index = object.atoms.items[shndx]; |
| 1539 | 1605 | if (self.atom(atom_index)) |atom_ptr| { |
| 1540 | | atom_ptr.alive = false; |
| 1606 | atom_ptr.flags.alive = false; |
| 1541 | 1607 | // atom_ptr.markFdesDead(self); |
| 1542 | 1608 | } |
| 1543 | 1609 | } |
| ... | ... | @@ -1645,25 +1711,26 @@ fn scanRelocs(self: *Elf) !void { |
| 1645 | 1711 | fn allocateObjects(self: *Elf) !void { |
| 1646 | 1712 | for (self.objects.items) |index| { |
| 1647 | 1713 | const object = self.file(index).?.object; |
| 1714 | |
| 1648 | 1715 | for (object.atoms.items) |atom_index| { |
| 1649 | 1716 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1650 | | if (!atom_ptr.alive) continue; |
| 1717 | if (!atom_ptr.flags.alive or atom_ptr.flags.allocated) continue; |
| 1651 | 1718 | try atom_ptr.allocate(self); |
| 1652 | 1719 | } |
| 1653 | 1720 | |
| 1654 | 1721 | for (object.locals()) |local_index| { |
| 1655 | 1722 | const local = self.symbol(local_index); |
| 1656 | 1723 | const atom_ptr = local.atom(self) orelse continue; |
| 1657 | | if (!atom_ptr.alive) continue; |
| 1658 | | local.value += atom_ptr.value; |
| 1724 | if (!atom_ptr.flags.alive) continue; |
| 1725 | local.value = local.elfSym(self).st_value + atom_ptr.value; |
| 1659 | 1726 | } |
| 1660 | 1727 | |
| 1661 | 1728 | for (object.globals()) |global_index| { |
| 1662 | 1729 | const global = self.symbol(global_index); |
| 1663 | 1730 | const atom_ptr = global.atom(self) orelse continue; |
| 1664 | | if (!atom_ptr.alive) continue; |
| 1731 | if (!atom_ptr.flags.alive) continue; |
| 1665 | 1732 | if (global.file_index == index) { |
| 1666 | | global.value += atom_ptr.value; |
| 1733 | global.value = global.elfSym(self).st_value + atom_ptr.value; |
| 1667 | 1734 | } |
| 1668 | 1735 | } |
| 1669 | 1736 | } |
| ... | ... | @@ -1676,7 +1743,7 @@ fn writeObjects(self: *Elf) !void { |
| 1676 | 1743 | const object = self.file(index).?.object; |
| 1677 | 1744 | for (object.atoms.items) |atom_index| { |
| 1678 | 1745 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1679 | | if (!atom_ptr.alive) continue; |
| 1746 | if (!atom_ptr.flags.alive) continue; |
| 1680 | 1747 | |
| 1681 | 1748 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1682 | 1749 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| ... | ... | @@ -2650,7 +2717,7 @@ fn updateDeclCode( |
| 2650 | 2717 | atom_ptr.output_section_index = shdr_index; |
| 2651 | 2718 | |
| 2652 | 2719 | sym.name_offset = try self.strtab.insert(gpa, decl_name); |
| 2653 | | atom_ptr.alive = true; |
| 2720 | atom_ptr.flags.alive = true; |
| 2654 | 2721 | atom_ptr.name_offset = sym.name_offset; |
| 2655 | 2722 | esym.st_name = sym.name_offset; |
| 2656 | 2723 | esym.st_info |= stt_bits; |
| ... | ... | @@ -2681,11 +2748,6 @@ fn updateDeclCode( |
| 2681 | 2748 | } else { |
| 2682 | 2749 | try atom_ptr.allocate(self); |
| 2683 | 2750 | 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 | 2751 | |
| 2690 | 2752 | sym.value = atom_ptr.value; |
| 2691 | 2753 | esym.st_value = atom_ptr.value; |
| ... | ... | @@ -2873,7 +2935,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2873 | 2935 | defer gpa.free(name); |
| 2874 | 2936 | break :blk try self.strtab.insert(gpa, name); |
| 2875 | 2937 | }; |
| 2876 | | const name = self.strtab.get(name_str_index).?; |
| 2877 | 2938 | |
| 2878 | 2939 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 2879 | 2940 | mod.declPtr(owner_decl).srcLoc(mod) |
| ... | ... | @@ -2913,7 +2974,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2913 | 2974 | local_esym.st_info |= elf.STT_OBJECT; |
| 2914 | 2975 | local_esym.st_size = code.len; |
| 2915 | 2976 | const atom_ptr = local_sym.atom(self).?; |
| 2916 | | atom_ptr.alive = true; |
| 2977 | atom_ptr.flags.alive = true; |
| 2917 | 2978 | atom_ptr.name_offset = name_str_index; |
| 2918 | 2979 | atom_ptr.alignment = required_alignment; |
| 2919 | 2980 | atom_ptr.size = code.len; |
| ... | ... | @@ -2922,12 +2983,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2922 | 2983 | try atom_ptr.allocate(self); |
| 2923 | 2984 | errdefer self.freeDeclMetadata(symbol_index); |
| 2924 | 2985 | |
| 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 | 2986 | local_sym.value = atom_ptr.value; |
| 2932 | 2987 | local_esym.st_value = atom_ptr.value; |
| 2933 | 2988 | |
| ... | ... | @@ -2961,7 +3016,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2961 | 3016 | defer gpa.free(name); |
| 2962 | 3017 | break :blk try self.strtab.insert(gpa, name); |
| 2963 | 3018 | }; |
| 2964 | | const name = self.strtab.get(name_str_index).?; |
| 2965 | 3019 | |
| 2966 | 3020 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2967 | 3021 | const sym_index = try zig_module.addAtom(self); |
| ... | ... | @@ -2992,7 +3046,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2992 | 3046 | local_esym.st_info |= elf.STT_OBJECT; |
| 2993 | 3047 | local_esym.st_size = code.len; |
| 2994 | 3048 | const atom_ptr = local_sym.atom(self).?; |
| 2995 | | atom_ptr.alive = true; |
| 3049 | atom_ptr.flags.alive = true; |
| 2996 | 3050 | atom_ptr.name_offset = name_str_index; |
| 2997 | 3051 | atom_ptr.alignment = required_alignment; |
| 2998 | 3052 | atom_ptr.size = code.len; |
| ... | ... | @@ -3001,8 +3055,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 3001 | 3055 | try atom_ptr.allocate(self); |
| 3002 | 3056 | errdefer self.freeDeclMetadata(sym_index); |
| 3003 | 3057 | |
| 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 | 3058 | local_sym.value = atom_ptr.value; |
| 3007 | 3059 | local_esym.st_value = atom_ptr.value; |
| 3008 | 3060 | |
| ... | ... | @@ -3740,14 +3792,6 @@ pub fn calcImageBase(self: Elf) u64 { |
| 3740 | 3792 | }; |
| 3741 | 3793 | } |
| 3742 | 3794 | |
| 3743 | | pub fn defaultEntryAddress(self: Elf) u64 { |
| 3744 | | if (self.entry_addr) |addr| return addr; |
| 3745 | | return switch (self.base.options.target.cpu.arch) { |
| 3746 | | .spu_2 => 0, |
| 3747 | | else => default_entry_addr, |
| 3748 | | }; |
| 3749 | | } |
| 3750 | | |
| 3751 | 3795 | pub fn isDynLib(self: Elf) bool { |
| 3752 | 3796 | return self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic; |
| 3753 | 3797 | } |