| author | |
| committer | |
| log | 69738a07c2309530463873538a5fd62d6174a26c |
| tree | c41387ed1828fe5b053f5555bea6c880206999bc |
| parent | 6ad5db030c576ab9cf944b4a9432954681af649c |
4 files changed, 69 insertions(+), 56 deletions(-)
src/link/Elf.zig+25-11| ... | ... | @@ -834,10 +834,23 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 834 | 834 | try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset); |
| 835 | 835 | } |
| 836 | 836 | |
| 837 | if (self.zig_module_index == null) { | |
| 838 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | |
| 839 | self.files.set(index, .{ .zig_module = .{ .index = index } }); | |
| 840 | self.zig_module_index = index; | |
| 837 | if (self.base.options.module) |module| { | |
| 838 | if (self.zig_module_index == null) { | |
| 839 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | |
| 840 | self.files.set(index, .{ .zig_module = .{ | |
| 841 | .index = index, | |
| 842 | .path = module.main_pkg.root_src_path, | |
| 843 | } }); | |
| 844 | self.zig_module_index = index; | |
| 845 | const zig_module = self.file(index).?.zig_module; | |
| 846 | const sym_index = try zig_module.addLocal(self); | |
| 847 | const sym = self.symbol(sym_index); | |
| 848 | const esym = sym.sourceSymbol(self); | |
| 849 | const name_off = try self.strtab.insert(gpa, std.fs.path.stem(module.main_pkg.root_src_path)); | |
| 850 | sym.name_offset = name_off; | |
| 851 | esym.st_name = name_off; | |
| 852 | esym.st_info |= elf.STT_FILE; | |
| 853 | } | |
| 841 | 854 | } |
| 842 | 855 | } |
| 843 | 856 | |
| ... | ... | @@ -846,13 +859,12 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 846 | 859 | const shdr = &self.sections.items(.shdr)[shdr_index]; |
| 847 | 860 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; |
| 848 | 861 | const phdr = &self.program_headers.items[phdr_index]; |
| 849 | const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index]; | |
| 862 | const last_atom_index = self.sections.items(.last_atom_index)[shdr_index]; | |
| 850 | 863 | |
| 851 | 864 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 852 | 865 | // Must move the entire section. |
| 853 | 866 | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 854 | const existing_size = if (maybe_last_atom_index) |last_atom_index| blk: { | |
| 855 | const last = self.atom(last_atom_index); | |
| 867 | const existing_size = if (self.atom(last_atom_index)) |last| blk: { | |
| 856 | 868 | break :blk (last.value + last.size) - phdr.p_vaddr; |
| 857 | 869 | } else if (shdr_index == self.got_section_index.?) blk: { |
| 858 | 870 | break :blk shdr.sh_size; |
| ... | ... | @@ -1016,7 +1028,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1016 | 1028 | while (it.next()) |entry| { |
| 1017 | 1029 | const atom_index = entry.key_ptr.*; |
| 1018 | 1030 | const relocs = entry.value_ptr.*; |
| 1019 | const atom_ptr = self.atom(atom_index); | |
| 1031 | const atom_ptr = self.atom(atom_index).?; | |
| 1020 | 1032 | const source_shdr = self.sections.items(.shdr)[atom_ptr.output_section_index]; |
| 1021 | 1033 | |
| 1022 | 1034 | log.debug("relocating '{s}'", .{atom_ptr.name(self)}); |
| ... | ... | @@ -2753,6 +2765,7 @@ fn writeSymtab(self: *Elf) !void { |
| 2753 | 2765 | |
| 2754 | 2766 | const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms); |
| 2755 | 2767 | defer gpa.free(symtab); |
| 2768 | symtab[0] = null_sym; | |
| 2756 | 2769 | |
| 2757 | 2770 | var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{ |
| 2758 | 2771 | .ilocal = 1, |
| ... | ... | @@ -3083,7 +3096,8 @@ const CsuObjects = struct { |
| 3083 | 3096 | } |
| 3084 | 3097 | }; |
| 3085 | 3098 | |
| 3086 | pub fn atom(self: *Elf, atom_index: Atom.Index) *Atom { | |
| 3099 | pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom { | |
| 3100 | if (atom_index == 0) return null; | |
| 3087 | 3101 | assert(atom_index < self.atoms.items.len); |
| 3088 | 3102 | return &self.atoms.items[atom_index]; |
| 3089 | 3103 | } |
| ... | ... | @@ -3210,7 +3224,7 @@ fn fmtDumpState( |
| 3210 | 3224 | |
| 3211 | 3225 | if (self.zig_module_index) |index| { |
| 3212 | 3226 | const zig_module = self.file(index).?.zig_module; |
| 3213 | try writer.print("zig_module({d}) : (zig module)\n", .{index}); | |
| 3227 | try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path }); | |
| 3214 | 3228 | try writer.print("{}\n", .{zig_module.fmtSymtab(self)}); |
| 3215 | 3229 | } |
| 3216 | 3230 | if (self.linker_defined_index) |index| { |
| ... | ... | @@ -3230,7 +3244,7 @@ const Section = struct { |
| 3230 | 3244 | phdr_index: u16, |
| 3231 | 3245 | |
| 3232 | 3246 | /// Index of the last allocated atom in this section. |
| 3233 | last_atom_index: ?Atom.Index = null, | |
| 3247 | last_atom_index: Atom.Index = 0, | |
| 3234 | 3248 | |
| 3235 | 3249 | /// A list of atoms that have surplus capacity. This list can have false |
| 3236 | 3250 | /// positives, as functions grow and shrink over time, only sometimes being added |
src/link/Elf/Atom.zig+27-33| ... | ... | @@ -39,8 +39,8 @@ fde_end: u32 = 0, |
| 39 | 39 | |
| 40 | 40 | /// Points to the previous and next neighbors, based on the `text_offset`. |
| 41 | 41 | /// This can be used to find, for example, the capacity of this `TextBlock`. |
| 42 | prev_index: ?Index = null, | |
| 43 | next_index: ?Index = null, | |
| 42 | prev_index: Index = 0, | |
| 43 | next_index: Index = 0, | |
| 44 | 44 | |
| 45 | 45 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 46 | 46 | return elf_file.strtab.getAssumeExists(self.name_offset); |
| ... | ... | @@ -50,14 +50,13 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 50 | 50 | /// File offset relocation happens transparently, so it is not included in |
| 51 | 51 | /// this calculation. |
| 52 | 52 | pub fn capacity(self: Atom, elf_file: *Elf) u64 { |
| 53 | const next_value = if (self.next_index) |next_index| elf_file.atom(next_index).value else std.math.maxInt(u32); | |
| 53 | const next_value = if (elf_file.atom(self.next_index)) |next| next.value else std.math.maxInt(u32); | |
| 54 | 54 | return next_value - self.value; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | 57 | pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { |
| 58 | 58 | // No need to keep a free list node for the last block. |
| 59 | const next_index = self.next_index orelse return false; | |
| 60 | const next = elf_file.atom(next_index); | |
| 59 | const next = elf_file.atom(self.next_index) orelse return false; | |
| 61 | 60 | const cap = next.value - self.value; |
| 62 | 61 | const ideal_cap = Elf.padToIdeal(self.size); |
| 63 | 62 | if (cap <= ideal_cap) return false; |
| ... | ... | @@ -84,7 +83,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 84 | 83 | const phdr = &elf_file.program_headers.items[phdr_index]; |
| 85 | 84 | const shdr = &elf_file.sections.items(.shdr)[self.output_section_index]; |
| 86 | 85 | const free_list = &elf_file.sections.items(.free_list)[self.output_section_index]; |
| 87 | const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index]; | |
| 86 | const last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index]; | |
| 88 | 87 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); |
| 89 | 88 | const alignment = try std.math.powi(u64, 2, self.alignment); |
| 90 | 89 | |
| ... | ... | @@ -102,7 +101,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 102 | 101 | var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len; |
| 103 | 102 | while (i < free_list.items.len) { |
| 104 | 103 | const big_atom_index = free_list.items[i]; |
| 105 | const big_atom = elf_file.atom(big_atom_index); | |
| 104 | const big_atom = elf_file.atom(big_atom_index).?; | |
| 106 | 105 | // We now have a pointer to a live atom that has too much capacity. |
| 107 | 106 | // Is it enough that we could fit this new atom? |
| 108 | 107 | const cap = big_atom.capacity(elf_file); |
| ... | ... | @@ -134,13 +133,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 134 | 133 | free_list_removal = i; |
| 135 | 134 | } |
| 136 | 135 | break :blk new_start_vaddr; |
| 137 | } else if (maybe_last_atom_index.*) |last_index| { | |
| 138 | const last = elf_file.atom(last_index); | |
| 136 | } else if (elf_file.atom(last_atom_index.*)) |last| { | |
| 139 | 137 | const ideal_capacity = Elf.padToIdeal(last.size); |
| 140 | 138 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; |
| 141 | 139 | const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment); |
| 142 | 140 | // Set up the metadata to be updated, after errors are no longer possible. |
| 143 | atom_placement = last_index; | |
| 141 | atom_placement = last.atom_index; | |
| 144 | 142 | break :blk new_start_vaddr; |
| 145 | 143 | } else { |
| 146 | 144 | break :blk phdr.p_vaddr; |
| ... | ... | @@ -148,13 +146,13 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 148 | 146 | }; |
| 149 | 147 | |
| 150 | 148 | const expand_section = if (atom_placement) |placement_index| |
| 151 | elf_file.atom(placement_index).next_index == null | |
| 149 | elf_file.atom(placement_index).?.next_index == 0 | |
| 152 | 150 | else |
| 153 | 151 | true; |
| 154 | 152 | if (expand_section) { |
| 155 | 153 | const needed_size = (self.value + self.size) - phdr.p_vaddr; |
| 156 | 154 | try elf_file.growAllocSection(self.output_section_index, needed_size); |
| 157 | maybe_last_atom_index.* = self.atom_index; | |
| 155 | last_atom_index.* = self.atom_index; | |
| 158 | 156 | |
| 159 | 157 | if (elf_file.dwarf) |_| { |
| 160 | 158 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address |
| ... | ... | @@ -172,23 +170,21 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 172 | 170 | // This function can also reallocate an atom. |
| 173 | 171 | // In this case we need to "unplug" it from its previous location before |
| 174 | 172 | // plugging it in to its new location. |
| 175 | if (self.prev_index) |prev_index| { | |
| 176 | const prev = elf_file.atom(prev_index); | |
| 173 | if (elf_file.atom(self.prev_index)) |prev| { | |
| 177 | 174 | prev.next_index = self.next_index; |
| 178 | 175 | } |
| 179 | if (self.next_index) |next_index| { | |
| 180 | const next = elf_file.atom(next_index); | |
| 176 | if (elf_file.atom(self.next_index)) |next| { | |
| 181 | 177 | next.prev_index = self.prev_index; |
| 182 | 178 | } |
| 183 | 179 | |
| 184 | 180 | if (atom_placement) |big_atom_index| { |
| 185 | const big_atom = elf_file.atom(big_atom_index); | |
| 181 | const big_atom = elf_file.atom(big_atom_index).?; | |
| 186 | 182 | self.prev_index = big_atom_index; |
| 187 | 183 | self.next_index = big_atom.next_index; |
| 188 | 184 | big_atom.next_index = self.atom_index; |
| 189 | 185 | } else { |
| 190 | self.prev_index = null; | |
| 191 | self.next_index = null; | |
| 186 | self.prev_index = 0; | |
| 187 | self.next_index = 0; | |
| 192 | 188 | } |
| 193 | 189 | if (free_list_removal) |i| { |
| 194 | 190 | _ = free_list.swapRemove(i); |
| ... | ... | @@ -231,35 +227,33 @@ pub fn free(self: *Atom, elf_file: *Elf) void { |
| 231 | 227 | } |
| 232 | 228 | } |
| 233 | 229 | |
| 234 | const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx]; | |
| 235 | if (maybe_last_atom_index.*) |last_atom_index| { | |
| 236 | if (last_atom_index == self.atom_index) { | |
| 237 | if (self.prev_index) |prev_index| { | |
| 230 | const last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx]; | |
| 231 | if (elf_file.atom(last_atom_index.*)) |last_atom| { | |
| 232 | if (last_atom.atom_index == self.atom_index) { | |
| 233 | if (elf_file.atom(self.prev_index)) |_| { | |
| 238 | 234 | // TODO shrink the section size here |
| 239 | maybe_last_atom_index.* = prev_index; | |
| 235 | last_atom_index.* = self.prev_index; | |
| 240 | 236 | } else { |
| 241 | maybe_last_atom_index.* = null; | |
| 237 | last_atom_index.* = 0; | |
| 242 | 238 | } |
| 243 | 239 | } |
| 244 | 240 | } |
| 245 | 241 | |
| 246 | if (self.prev_index) |prev_index| { | |
| 247 | const prev = elf_file.atom(prev_index); | |
| 242 | if (elf_file.atom(self.prev_index)) |prev| { | |
| 248 | 243 | prev.next_index = self.next_index; |
| 249 | ||
| 250 | 244 | if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) { |
| 251 | 245 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| 252 | 246 | // ignore the OOM here. |
| 253 | free_list.append(gpa, prev_index) catch {}; | |
| 247 | free_list.append(gpa, prev.atom_index) catch {}; | |
| 254 | 248 | } |
| 255 | 249 | } else { |
| 256 | self.prev_index = null; | |
| 250 | self.prev_index = 0; | |
| 257 | 251 | } |
| 258 | 252 | |
| 259 | if (self.next_index) |next_index| { | |
| 260 | elf_file.atom(next_index).prev_index = self.prev_index; | |
| 253 | if (elf_file.atom(self.next_index)) |next| { | |
| 254 | next.prev_index = self.prev_index; | |
| 261 | 255 | } else { |
| 262 | self.next_index = null; | |
| 256 | self.next_index = 0; | |
| 263 | 257 | } |
| 264 | 258 | |
| 265 | 259 | self.* = .{}; |
src/link/Elf/Symbol.zig+2-2| ... | ... | @@ -36,7 +36,7 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { |
| 36 | 36 | const file_ptr = symbol.file(elf_file).?; |
| 37 | 37 | // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS; |
| 38 | 38 | return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and |
| 39 | file_ptr != .linker_defined and file_ptr != .zig_module; | |
| 39 | file_ptr != .linker_defined; | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | pub fn isLocal(symbol: Symbol) bool { |
| ... | ... | @@ -175,7 +175,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 175 | 175 | const st_shndx = blk: { |
| 176 | 176 | // if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?; |
| 177 | 177 | // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; |
| 178 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module) | |
| 178 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) | |
| 179 | 179 | break :blk elf.SHN_ABS; |
| 180 | 180 | break :blk symbol.output_section_index; |
| 181 | 181 | }; |
src/link/Elf/ZigModule.zig+15-10| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | /// Path is owned by Module and lives as long as *Module. | |
| 2 | path: []const u8, | |
| 1 | 3 | index: File.Index, |
| 2 | 4 | |
| 3 | 5 | elf_local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| ... | ... | @@ -23,26 +25,29 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void { |
| 23 | 25 | pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index { |
| 24 | 26 | const gpa = elf_file.base.allocator; |
| 25 | 27 | const atom_index = try elf_file.addAtom(); |
| 26 | const symbol_index = try elf_file.addSymbol(); | |
| 27 | ||
| 28 | const atom_ptr = elf_file.atom(atom_index); | |
| 28 | const symbol_index = try self.addLocal(elf_file); | |
| 29 | const atom_ptr = elf_file.atom(atom_index).?; | |
| 29 | 30 | atom_ptr.file_index = self.index; |
| 30 | 31 | atom_ptr.output_section_index = output_section_index; |
| 31 | ||
| 32 | 32 | const symbol_ptr = elf_file.symbol(symbol_index); |
| 33 | symbol_ptr.file_index = self.index; | |
| 34 | 33 | symbol_ptr.atom_index = atom_index; |
| 35 | 34 | symbol_ptr.output_section_index = output_section_index; |
| 36 | symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len)); | |
| 35 | const local_esym = symbol_ptr.sourceSymbol(elf_file); | |
| 36 | local_esym.st_shndx = output_section_index; | |
| 37 | try self.atoms.append(gpa, atom_index); | |
| 38 | return symbol_index; | |
| 39 | } | |
| 37 | 40 | |
| 41 | pub fn addLocal(self: *ZigModule, elf_file: *Elf) !Symbol.Index { | |
| 42 | const gpa = elf_file.base.allocator; | |
| 43 | const symbol_index = try elf_file.addSymbol(); | |
| 44 | const symbol_ptr = elf_file.symbol(symbol_index); | |
| 45 | symbol_ptr.file_index = self.index; | |
| 46 | symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len)); | |
| 38 | 47 | const local_esym = try self.elf_local_symbols.addOne(gpa); |
| 39 | 48 | local_esym.* = Elf.null_sym; |
| 40 | 49 | local_esym.st_info = elf.STB_LOCAL << 4; |
| 41 | local_esym.st_shndx = output_section_index; | |
| 42 | ||
| 43 | try self.atoms.append(gpa, atom_index); | |
| 44 | 50 | try self.local_symbols.putNoClobber(gpa, symbol_index, {}); |
| 45 | ||
| 46 | 51 | return symbol_index; |
| 47 | 52 | } |
| 48 | 53 |