| ... | @@ -1,99 +1,3 @@ | ... | @@ -1,99 +1,3 @@ |
| 1 | const Elf = @This(); | | |
| 2 | | | |
| 3 | const std = @import("std"); | | |
| 4 | const build_options = @import("build_options"); | | |
| 5 | const builtin = @import("builtin"); | | |
| 6 | const assert = std.debug.assert; | | |
| 7 | const elf = std.elf; | | |
| 8 | const fs = std.fs; | | |
| 9 | const log = std.log.scoped(.link); | | |
| 10 | const math = std.math; | | |
| 11 | const mem = std.mem; | | |
| 12 | | | |
| 13 | const codegen = @import("../codegen.zig"); | | |
| 14 | const glibc = @import("../glibc.zig"); | | |
| 15 | const link = @import("../link.zig"); | | |
| 16 | const lldMain = @import("../main.zig").lldMain; | | |
| 17 | const musl = @import("../musl.zig"); | | |
| 18 | const target_util = @import("../target.zig"); | | |
| 19 | const trace = @import("../tracy.zig").trace; | | |
| 20 | | | |
| 21 | const Air = @import("../Air.zig"); | | |
| 22 | const Allocator = std.mem.Allocator; | | |
| 23 | pub const Atom = @import("Elf/Atom.zig"); | | |
| 24 | const Cache = std.Build.Cache; | | |
| 25 | const Compilation = @import("../Compilation.zig"); | | |
| 26 | const Dwarf = @import("Dwarf.zig"); | | |
| 27 | const File = link.File; | | |
| 28 | const Liveness = @import("../Liveness.zig"); | | |
| 29 | const LlvmObject = @import("../codegen/llvm.zig").Object; | | |
| 30 | const Module = @import("../Module.zig"); | | |
| 31 | const InternPool = @import("../InternPool.zig"); | | |
| 32 | const Package = @import("../Package.zig"); | | |
| 33 | const StringTable = @import("strtab.zig").StringTable; | | |
| 34 | const TableSection = @import("table_section.zig").TableSection; | | |
| 35 | const Type = @import("../type.zig").Type; | | |
| 36 | const TypedValue = @import("../TypedValue.zig"); | | |
| 37 | const Value = @import("../value.zig").Value; | | |
| 38 | | | |
| 39 | const default_entry_addr = 0x8000000; | | |
| 40 | | | |
| 41 | pub const base_tag: File.Tag = .elf; | | |
| 42 | | | |
| 43 | const Section = struct { | | |
| 44 | shdr: elf.Elf64_Shdr, | | |
| 45 | phdr_index: u16, | | |
| 46 | | | |
| 47 | /// Index of the last allocated atom in this section. | | |
| 48 | last_atom_index: ?Atom.Index = null, | | |
| 49 | | | |
| 50 | /// A list of atoms that have surplus capacity. This list can have false | | |
| 51 | /// positives, as functions grow and shrink over time, only sometimes being added | | |
| 52 | /// or removed from the freelist. | | |
| 53 | /// | | |
| 54 | /// An atom has surplus capacity when its overcapacity value is greater than | | |
| 55 | /// padToIdeal(minimum_atom_size). That is, when it has so | | |
| 56 | /// much extra capacity, that we could fit a small new symbol in it, itself with | | |
| 57 | /// ideal_capacity or more. | | |
| 58 | /// | | |
| 59 | /// Ideal capacity is defined by size + (size / ideal_factor) | | |
| 60 | /// | | |
| 61 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that | | |
| 62 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | | |
| 63 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | | |
| 64 | /// by 1 byte. It will then have -1 overcapacity. | | |
| 65 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | | |
| 66 | }; | | |
| 67 | | | |
| 68 | const LazySymbolMetadata = struct { | | |
| 69 | const State = enum { unused, pending_flush, flushed }; | | |
| 70 | text_atom: Atom.Index = undefined, | | |
| 71 | rodata_atom: Atom.Index = undefined, | | |
| 72 | text_state: State = .unused, | | |
| 73 | rodata_state: State = .unused, | | |
| 74 | }; | | |
| 75 | | | |
| 76 | const DeclMetadata = struct { | | |
| 77 | atom: Atom.Index, | | |
| 78 | shdr: u16, | | |
| 79 | /// A list of all exports aliases of this Decl. | | |
| 80 | exports: std.ArrayListUnmanaged(u32) = .{}, | | |
| 81 | | | |
| 82 | fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 { | | |
| 83 | for (m.exports.items) |exp| { | | |
| 84 | if (mem.eql(u8, name, elf_file.getGlobalName(exp))) return exp; | | |
| 85 | } | | |
| 86 | return null; | | |
| 87 | } | | |
| 88 | | | |
| 89 | fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { | | |
| 90 | for (m.exports.items) |*exp| { | | |
| 91 | if (mem.eql(u8, name, elf_file.getGlobalName(exp.*))) return exp; | | |
| 92 | } | | |
| 93 | return null; | | |
| 94 | } | | |
| 95 | }; | | |
| 96 | | | |
| 97 | base: File, | 1 | base: File, |
| 98 | dwarf: ?Dwarf = null, | 2 | dwarf: ?Dwarf = null, |
| 99 | | 3 | |
| ... | @@ -151,11 +55,13 @@ strtab_section_index: ?u16 = null, | ... | @@ -151,11 +55,13 @@ strtab_section_index: ?u16 = null, |
| 151 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and | 55 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and |
| 152 | /// write them at the end. These are only the local symbols. The length of this array | 56 | /// write them at the end. These are only the local symbols. The length of this array |
| 153 | /// is the value used for sh_info in the .symtab section. | 57 | /// is the value used for sh_info in the .symtab section. |
| 154 | local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | 58 | locals: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 155 | global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | 59 | globals: std.ArrayListUnmanaged(u32) = .{}, |
| | 60 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| | 61 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 156 | | 62 | |
| 157 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 63 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 158 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 64 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 159 | | 65 | |
| 160 | got_table: TableSection(u32) = .{}, | 66 | got_table: TableSection(u32) = .{}, |
| 161 | | 67 | |
| ... | @@ -247,14 +153,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -247,14 +153,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 247 | self.shdr_table_dirty = true; | 153 | self.shdr_table_dirty = true; |
| 248 | | 154 | |
| 249 | // Index 0 is always a null symbol. | 155 | // Index 0 is always a null symbol. |
| 250 | try self.local_symbols.append(allocator, .{ | 156 | try self.locals.append(allocator, null_sym); |
| 251 | .st_name = 0, | | |
| 252 | .st_info = 0, | | |
| 253 | .st_other = 0, | | |
| 254 | .st_shndx = 0, | | |
| 255 | .st_value = 0, | | |
| 256 | .st_size = 0, | | |
| 257 | }); | | |
| 258 | | 157 | |
| 259 | // There must always be a null section in index 0 | 158 | // There must always be a null section in index 0 |
| 260 | try self.sections.append(allocator, .{ | 159 | try self.sections.append(allocator, .{ |
| ... | @@ -329,11 +228,20 @@ pub fn deinit(self: *Elf) void { | ... | @@ -329,11 +228,20 @@ pub fn deinit(self: *Elf) void { |
| 329 | self.program_headers.deinit(gpa); | 228 | self.program_headers.deinit(gpa); |
| 330 | self.shstrtab.deinit(gpa); | 229 | self.shstrtab.deinit(gpa); |
| 331 | self.strtab.deinit(gpa); | 230 | self.strtab.deinit(gpa); |
| 332 | self.local_symbols.deinit(gpa); | 231 | self.locals.deinit(gpa); |
| 333 | self.global_symbols.deinit(gpa); | 232 | self.globals.deinit(gpa); |
| 334 | self.global_symbol_free_list.deinit(gpa); | 233 | self.globals_free_list.deinit(gpa); |
| 335 | self.local_symbol_free_list.deinit(gpa); | 234 | self.locals_free_list.deinit(gpa); |
| 336 | self.got_table.deinit(gpa); | 235 | self.got_table.deinit(gpa); |
| | 236 | self.unresolved.deinit(gpa); |
| | 237 | |
| | 238 | { |
| | 239 | var it = self.resolver.keyIterator(); |
| | 240 | while (it.next()) |key_ptr| { |
| | 241 | gpa.free(key_ptr.*); |
| | 242 | } |
| | 243 | self.resolver.deinit(gpa); |
| | 244 | } |
| 337 | | 245 | |
| 338 | { | 246 | { |
| 339 | var it = self.decls.iterator(); | 247 | var it = self.decls.iterator(); |
| ... | @@ -743,7 +651,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -743,7 +651,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 743 | .sh_size = file_size, | 651 | .sh_size = file_size, |
| 744 | // The section header index of the associated string table. | 652 | // The section header index of the associated string table. |
| 745 | .sh_link = self.strtab_section_index.?, | 653 | .sh_link = self.strtab_section_index.?, |
| 746 | .sh_info = @as(u32, @intCast(self.local_symbols.items.len)), | 654 | .sh_info = @as(u32, @intCast(self.locals.items.len)), |
| 747 | .sh_addralign = min_align, | 655 | .sh_addralign = min_align, |
| 748 | .sh_entsize = each_size, | 656 | .sh_entsize = each_size, |
| 749 | }, | 657 | }, |
| ... | @@ -908,7 +816,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -908,7 +816,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 908 | | 816 | |
| 909 | { | 817 | { |
| 910 | // Iterate over symbols, populating free_list and last_text_block. | 818 | // Iterate over symbols, populating free_list and last_text_block. |
| 911 | if (self.local_symbols.items.len != 1) { | 819 | if (self.locals.items.len != 1) { |
| 912 | @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); | 820 | @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); |
| 913 | } | 821 | } |
| 914 | // We are starting with an empty file. The default values are correct, null and empty list. | 822 | // We are starting with an empty file. The default values are correct, null and empty list. |
| ... | @@ -1109,7 +1017,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1109,7 +1017,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1109 | log.debug("relocating '{?s}'", .{self.strtab.get(source_sym.st_name)}); | 1017 | log.debug("relocating '{?s}'", .{self.strtab.get(source_sym.st_name)}); |
| 1110 | | 1018 | |
| 1111 | for (relocs.items) |*reloc| { | 1019 | for (relocs.items) |*reloc| { |
| 1112 | const target_sym = self.local_symbols.items[reloc.target]; | 1020 | const target_sym = self.locals.items[reloc.target]; |
| 1113 | const target_vaddr = target_sym.st_value + reloc.addend; | 1021 | const target_vaddr = target_sym.st_value + reloc.addend; |
| 1114 | | 1022 | |
| 1115 | if (target_vaddr == reloc.prev_vaddr) continue; | 1023 | if (target_vaddr == reloc.prev_vaddr) continue; |
| ... | @@ -2219,22 +2127,14 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { | ... | @@ -2219,22 +2127,14 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { |
| 2219 | } | 2127 | } |
| 2220 | | 2128 | |
| 2221 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 2129 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2222 | const local_sym_index = atom.getSymbolIndex().?; | 2130 | const sym_index = atom.getSymbolIndex().?; |
| 2223 | | 2131 | |
| 2224 | log.debug("adding %{d} to local symbols free list", .{local_sym_index}); | 2132 | log.debug("adding %{d} to local symbols free list", .{sym_index}); |
| 2225 | self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; | 2133 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 2226 | self.local_symbols.items[local_sym_index] = .{ | 2134 | self.locals.items[sym_index] = null_sym; |
| 2227 | .st_name = 0, | 2135 | _ = self.atom_by_index_table.remove(sym_index); |
| 2228 | .st_info = 0, | 2136 | self.getAtomPtr(atom_index).sym_index = 0; |
| 2229 | .st_other = 0, | 2137 | self.got_table.freeEntry(gpa, sym_index); |
| 2230 | .st_shndx = 0, | | |
| 2231 | .st_value = 0, | | |
| 2232 | .st_size = 0, | | |
| 2233 | }; | | |
| 2234 | _ = self.atom_by_index_table.remove(local_sym_index); | | |
| 2235 | self.getAtomPtr(atom_index).local_sym_index = 0; | | |
| 2236 | | | |
| 2237 | self.got_table.freeEntry(gpa, local_sym_index); | | |
| 2238 | } | 2138 | } |
| 2239 | | 2139 | |
| 2240 | fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { | 2140 | fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { |
| ... | @@ -2256,14 +2156,14 @@ pub fn createAtom(self: *Elf) !Atom.Index { | ... | @@ -2256,14 +2156,14 @@ pub fn createAtom(self: *Elf) !Atom.Index { |
| 2256 | const gpa = self.base.allocator; | 2156 | const gpa = self.base.allocator; |
| 2257 | const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len)); | 2157 | const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len)); |
| 2258 | const atom = try self.atoms.addOne(gpa); | 2158 | const atom = try self.atoms.addOne(gpa); |
| 2259 | const local_sym_index = try self.allocateLocalSymbol(); | 2159 | const sym_index = try self.allocateSymbol(); |
| 2260 | try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index); | 2160 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 2261 | atom.* = .{ | 2161 | atom.* = .{ |
| 2262 | .local_sym_index = local_sym_index, | 2162 | .sym_index = sym_index, |
| 2263 | .prev_index = null, | 2163 | .prev_index = null, |
| 2264 | .next_index = null, | 2164 | .next_index = null, |
| 2265 | }; | 2165 | }; |
| 2266 | log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index }); | 2166 | log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); |
| 2267 | return atom_index; | 2167 | return atom_index; |
| 2268 | } | 2168 | } |
| 2269 | | 2169 | |
| ... | @@ -2389,22 +2289,20 @@ fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignme | ... | @@ -2389,22 +2289,20 @@ fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignme |
| 2389 | return vaddr; | 2289 | return vaddr; |
| 2390 | } | 2290 | } |
| 2391 | | 2291 | |
| 2392 | pub fn allocateLocalSymbol(self: *Elf) !u32 { | 2292 | pub fn allocateSymbol(self: *Elf) !u32 { |
| 2393 | try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); | 2293 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 2394 | | | |
| 2395 | const index = blk: { | 2294 | const index = blk: { |
| 2396 | if (self.local_symbol_free_list.popOrNull()) |index| { | 2295 | if (self.locals_free_list.popOrNull()) |index| { |
| 2397 | log.debug(" (reusing symbol index {d})", .{index}); | 2296 | log.debug(" (reusing symbol index {d})", .{index}); |
| 2398 | break :blk index; | 2297 | break :blk index; |
| 2399 | } else { | 2298 | } else { |
| 2400 | log.debug(" (allocating symbol index {d})", .{self.local_symbols.items.len}); | 2299 | log.debug(" (allocating symbol index {d})", .{self.locals.items.len}); |
| 2401 | const index = @as(u32, @intCast(self.local_symbols.items.len)); | 2300 | const index = @as(u32, @intCast(self.locals.items.len)); |
| 2402 | _ = self.local_symbols.addOneAssumeCapacity(); | 2301 | _ = self.locals.addOneAssumeCapacity(); |
| 2403 | break :blk index; | 2302 | break :blk index; |
| 2404 | } | 2303 | } |
| 2405 | }; | 2304 | }; |
| 2406 | | 2305 | self.locals.items[index] = .{ |
| 2407 | self.local_symbols.items[index] = .{ | | |
| 2408 | .st_name = 0, | 2306 | .st_name = 0, |
| 2409 | .st_info = 0, | 2307 | .st_info = 0, |
| 2410 | .st_other = 0, | 2308 | .st_other = 0, |
| ... | @@ -2412,7 +2310,23 @@ pub fn allocateLocalSymbol(self: *Elf) !u32 { | ... | @@ -2412,7 +2310,23 @@ pub fn allocateLocalSymbol(self: *Elf) !u32 { |
| 2412 | .st_value = 0, | 2310 | .st_value = 0, |
| 2413 | .st_size = 0, | 2311 | .st_size = 0, |
| 2414 | }; | 2312 | }; |
| | 2313 | return index; |
| | 2314 | } |
| 2415 | | 2315 | |
| | 2316 | fn allocateGlobal(self: *Elf) !u32 { |
| | 2317 | try self.globals.ensureUnusedCapacity(self.base.allocator, 1); |
| | 2318 | const index = blk: { |
| | 2319 | if (self.globals_free_list.popOrNull()) |index| { |
| | 2320 | log.debug(" (reusing global index {d})", .{index}); |
| | 2321 | break :blk index; |
| | 2322 | } else { |
| | 2323 | log.debug(" (allocating symbol index {d})", .{self.globals.items.len}); |
| | 2324 | const index = @as(u32, @intCast(self.globals.items.len)); |
| | 2325 | _ = self.globals.addOneAssumeCapacity(); |
| | 2326 | break :blk index; |
| | 2327 | } |
| | 2328 | }; |
| | 2329 | self.globals.items[index] = 0; |
| 2416 | return index; | 2330 | return index; |
| 2417 | } | 2331 | } |
| 2418 | | 2332 | |
| ... | @@ -2896,8 +2810,6 @@ pub fn updateDeclExports( | ... | @@ -2896,8 +2810,6 @@ pub fn updateDeclExports( |
| 2896 | const decl_metadata = self.decls.getPtr(decl_index).?; | 2810 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 2897 | const shdr_index = decl_metadata.shdr; | 2811 | const shdr_index = decl_metadata.shdr; |
| 2898 | | 2812 | |
| 2899 | try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); | | |
| 2900 | | | |
| 2901 | for (exports) |exp| { | 2813 | for (exports) |exp| { |
| 2902 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | 2814 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); |
| 2903 | if (exp.opts.section.unwrap()) |section_name| { | 2815 | if (exp.opts.section.unwrap()) |section_name| { |
| ... | @@ -2905,7 +2817,7 @@ pub fn updateDeclExports( | ... | @@ -2905,7 +2817,7 @@ pub fn updateDeclExports( |
| 2905 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); | 2817 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2906 | mod.failed_exports.putAssumeCapacityNoClobber( | 2818 | mod.failed_exports.putAssumeCapacityNoClobber( |
| 2907 | exp, | 2819 | exp, |
| 2908 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}), | 2820 | try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}), |
| 2909 | ); | 2821 | ); |
| 2910 | continue; | 2822 | continue; |
| 2911 | } | 2823 | } |
| ... | @@ -2924,37 +2836,30 @@ pub fn updateDeclExports( | ... | @@ -2924,37 +2836,30 @@ pub fn updateDeclExports( |
| 2924 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); | 2836 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2925 | mod.failed_exports.putAssumeCapacityNoClobber( | 2837 | mod.failed_exports.putAssumeCapacityNoClobber( |
| 2926 | exp, | 2838 | exp, |
| 2927 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}), | 2839 | try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}), |
| 2928 | ); | 2840 | ); |
| 2929 | continue; | 2841 | continue; |
| 2930 | }, | 2842 | }, |
| 2931 | }; | 2843 | }; |
| 2932 | const stt_bits: u8 = @as(u4, @truncate(decl_sym.st_info)); | 2844 | const stt_bits: u8 = @as(u4, @truncate(decl_sym.st_info)); |
| 2933 | if (decl_metadata.getExport(self, exp_name)) |i| { | 2845 | |
| 2934 | const sym = &self.global_symbols.items[i]; | 2846 | const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { |
| 2935 | sym.* = .{ | 2847 | const sym_index = try self.allocateSymbol(); |
| 2936 | .st_name = try self.strtab.insert(gpa, exp_name), | 2848 | try decl_metadata.exports.append(gpa, sym_index); |
| 2937 | .st_info = (stb_bits << 4) | stt_bits, | 2849 | break :blk sym_index; |
| 2938 | .st_other = 0, | 2850 | }; |
| 2939 | .st_shndx = shdr_index, | 2851 | const sym = self.getSymbolPtr(sym_index); |
| 2940 | .st_value = decl_sym.st_value, | 2852 | sym.* = .{ |
| 2941 | .st_size = decl_sym.st_size, | 2853 | .st_name = try self.strtab.insert(gpa, exp_name), |
| 2942 | }; | 2854 | .st_info = (stb_bits << 4) | stt_bits, |
| 2943 | } else { | 2855 | .st_other = 0, |
| 2944 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { | 2856 | .st_shndx = shdr_index, |
| 2945 | _ = self.global_symbols.addOneAssumeCapacity(); | 2857 | .st_value = decl_sym.st_value, |
| 2946 | break :blk self.global_symbols.items.len - 1; | 2858 | .st_size = decl_sym.st_size, |
| 2947 | }; | 2859 | }; |
| 2948 | try decl_metadata.exports.append(gpa, @as(u32, @intCast(i))); | 2860 | const sym_name = self.getSymbolName(sym_index); |
| 2949 | self.global_symbols.items[i] = .{ | 2861 | const gop = try self.getOrPutGlobalPtr(sym_name); |
| 2950 | .st_name = try self.strtab.insert(gpa, exp_name), | 2862 | gop.value_ptr.* = sym_index; |
| 2951 | .st_info = (stb_bits << 4) | stt_bits, | | |
| 2952 | .st_other = 0, | | |
| 2953 | .st_shndx = shdr_index, | | |
| 2954 | .st_value = decl_sym.st_value, | | |
| 2955 | .st_size = decl_sym.st_size, | | |
| 2956 | }; | | |
| 2957 | } | | |
| 2958 | } | 2863 | } |
| 2959 | } | 2864 | } |
| 2960 | | 2865 | |
| ... | @@ -2981,10 +2886,20 @@ pub fn deleteDeclExport( | ... | @@ -2981,10 +2886,20 @@ pub fn deleteDeclExport( |
| 2981 | ) void { | 2886 | ) void { |
| 2982 | if (self.llvm_object) |_| return; | 2887 | if (self.llvm_object) |_| return; |
| 2983 | const metadata = self.decls.getPtr(decl_index) orelse return; | 2888 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| | 2889 | const gpa = self.base.allocator; |
| 2984 | const mod = self.base.options.module.?; | 2890 | const mod = self.base.options.module.?; |
| 2985 | const sym_index = metadata.getExportPtr(self, mod.intern_pool.stringToSlice(name)) orelse return; | 2891 | const exp_name = mod.intern_pool.stringToSlice(name); |
| 2986 | self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; | 2892 | const sym_index = metadata.getExportPtr(self, exp_name) orelse return; |
| 2987 | self.global_symbols.items[sym_index.*].st_info = 0; | 2893 | const sym = self.getSymbolPtr(sym_index.*); |
| | 2894 | log.debug("deleting export '{s}'", .{exp_name}); |
| | 2895 | sym.* = null_sym; |
| | 2896 | self.locals_free_list.append(gpa, sym_index.*) catch {}; |
| | 2897 | |
| | 2898 | if (self.resolver.fetchRemove(exp_name)) |entry| { |
| | 2899 | self.globals_free_list.append(gpa, entry.value) catch {}; |
| | 2900 | self.globals.items[entry.value] = 0; |
| | 2901 | } |
| | 2902 | |
| 2988 | sym_index.* = 0; | 2903 | sym_index.* = 0; |
| 2989 | } | 2904 | } |
| 2990 | | 2905 | |
| ... | @@ -3110,10 +3025,10 @@ fn writeSymbols(self: *Elf) !void { | ... | @@ -3110,10 +3025,10 @@ fn writeSymbols(self: *Elf) !void { |
| 3110 | }; | 3025 | }; |
| 3111 | | 3026 | |
| 3112 | const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?]; | 3027 | const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?]; |
| 3113 | shdr.sh_info = @intCast(self.local_symbols.items.len); | 3028 | shdr.sh_info = @intCast(self.locals.items.len); |
| 3114 | self.markDirty(self.symtab_section_index.?, null); | 3029 | self.markDirty(self.symtab_section_index.?, null); |
| 3115 | | 3030 | |
| 3116 | const nsyms = self.local_symbols.items.len + self.global_symbols.items.len; | 3031 | const nsyms = self.locals.items.len + self.globals.items.len; |
| 3117 | const needed_size = nsyms * sym_size; | 3032 | const needed_size = nsyms * sym_size; |
| 3118 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true); | 3033 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true); |
| 3119 | | 3034 | |
| ... | @@ -3124,15 +3039,15 @@ fn writeSymbols(self: *Elf) !void { | ... | @@ -3124,15 +3039,15 @@ fn writeSymbols(self: *Elf) !void { |
| 3124 | const buf = try gpa.alloc(elf.Elf32_Sym, nsyms); | 3039 | const buf = try gpa.alloc(elf.Elf32_Sym, nsyms); |
| 3125 | defer gpa.free(buf); | 3040 | defer gpa.free(buf); |
| 3126 | | 3041 | |
| 3127 | for (buf[0..self.local_symbols.items.len], self.local_symbols.items) |*sym, local| { | 3042 | for (buf[0..self.locals.items.len], self.locals.items) |*sym, local| { |
| 3128 | elf32SymFromSym(local, sym); | 3043 | elf32SymFromSym(local, sym); |
| 3129 | if (foreign_endian) { | 3044 | if (foreign_endian) { |
| 3130 | mem.byteSwapAllFields(elf.Elf32_Sym, sym); | 3045 | mem.byteSwapAllFields(elf.Elf32_Sym, sym); |
| 3131 | } | 3046 | } |
| 3132 | } | 3047 | } |
| 3133 | | 3048 | |
| 3134 | for (buf[self.local_symbols.items.len..], self.global_symbols.items) |*sym, global| { | 3049 | for (buf[self.locals.items.len..], self.globals.items) |*sym, global| { |
| 3135 | elf32SymFromSym(global, sym); | 3050 | elf32SymFromSym(self.getSymbol(global), sym); |
| 3136 | if (foreign_endian) { | 3051 | if (foreign_endian) { |
| 3137 | mem.byteSwapAllFields(elf.Elf32_Sym, sym); | 3052 | mem.byteSwapAllFields(elf.Elf32_Sym, sym); |
| 3138 | } | 3053 | } |
| ... | @@ -3142,15 +3057,15 @@ fn writeSymbols(self: *Elf) !void { | ... | @@ -3142,15 +3057,15 @@ fn writeSymbols(self: *Elf) !void { |
| 3142 | .p64 => { | 3057 | .p64 => { |
| 3143 | const buf = try gpa.alloc(elf.Elf64_Sym, nsyms); | 3058 | const buf = try gpa.alloc(elf.Elf64_Sym, nsyms); |
| 3144 | defer gpa.free(buf); | 3059 | defer gpa.free(buf); |
| 3145 | for (buf[0..self.local_symbols.items.len], self.local_symbols.items) |*sym, local| { | 3060 | for (buf[0..self.locals.items.len], self.locals.items) |*sym, local| { |
| 3146 | sym.* = local; | 3061 | sym.* = local; |
| 3147 | if (foreign_endian) { | 3062 | if (foreign_endian) { |
| 3148 | mem.byteSwapAllFields(elf.Elf64_Sym, sym); | 3063 | mem.byteSwapAllFields(elf.Elf64_Sym, sym); |
| 3149 | } | 3064 | } |
| 3150 | } | 3065 | } |
| 3151 | | 3066 | |
| 3152 | for (buf[self.local_symbols.items.len..], self.global_symbols.items) |*sym, global| { | 3067 | for (buf[self.locals.items.len..], self.globals.items) |*sym, global| { |
| 3153 | sym.* = global; | 3068 | sym.* = self.getSymbol(global); |
| 3154 | if (foreign_endian) { | 3069 | if (foreign_endian) { |
| 3155 | mem.byteSwapAllFields(elf.Elf64_Sym, sym); | 3070 | mem.byteSwapAllFields(elf.Elf64_Sym, sym); |
| 3156 | } | 3071 | } |
| ... | @@ -3450,11 +3365,12 @@ const CsuObjects = struct { | ... | @@ -3450,11 +3365,12 @@ const CsuObjects = struct { |
| 3450 | | 3365 | |
| 3451 | fn logSymtab(self: Elf) void { | 3366 | fn logSymtab(self: Elf) void { |
| 3452 | log.debug("locals:", .{}); | 3367 | log.debug("locals:", .{}); |
| 3453 | for (self.local_symbols.items, 0..) |sym, id| { | 3368 | for (self.locals.items, 0..) |sym, id| { |
| 3454 | log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.strtab.get(sym.st_name), sym.st_value, sym.st_shndx }); | 3369 | log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.strtab.get(sym.st_name), sym.st_value, sym.st_shndx }); |
| 3455 | } | 3370 | } |
| 3456 | log.debug("globals:", .{}); | 3371 | log.debug("globals:", .{}); |
| 3457 | for (self.global_symbols.items, 0..) |sym, id| { | 3372 | for (self.globals.items, 0..) |global, id| { |
| | 3373 | const sym = self.getSymbol(global); |
| 3458 | log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.strtab.get(sym.st_name), sym.st_value, sym.st_shndx }); | 3374 | log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.strtab.get(sym.st_name), sym.st_value, sym.st_shndx }); |
| 3459 | } | 3375 | } |
| 3460 | } | 3376 | } |
| ... | @@ -3471,24 +3387,61 @@ pub fn getProgramHeaderPtr(self: *Elf, shdr_index: u16) *elf.Elf64_Phdr { | ... | @@ -3471,24 +3387,61 @@ pub fn getProgramHeaderPtr(self: *Elf, shdr_index: u16) *elf.Elf64_Phdr { |
| 3471 | | 3387 | |
| 3472 | /// Returns pointer-to-symbol described at sym_index. | 3388 | /// Returns pointer-to-symbol described at sym_index. |
| 3473 | pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym { | 3389 | pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym { |
| 3474 | return &self.local_symbols.items[sym_index]; | 3390 | return &self.locals.items[sym_index]; |
| 3475 | } | 3391 | } |
| 3476 | | 3392 | |
| 3477 | /// Returns symbol at sym_index. | 3393 | /// Returns symbol at sym_index. |
| 3478 | pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym { | 3394 | pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym { |
| 3479 | return self.local_symbols.items[sym_index]; | 3395 | return self.locals.items[sym_index]; |
| 3480 | } | 3396 | } |
| 3481 | | 3397 | |
| 3482 | /// Returns name of the symbol at sym_index. | 3398 | /// Returns name of the symbol at sym_index. |
| 3483 | pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 { | 3399 | pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 { |
| 3484 | const sym = self.local_symbols.items[sym_index]; | 3400 | const sym = self.locals.items[sym_index]; |
| 3485 | return self.strtab.get(sym.st_name).?; | 3401 | return self.strtab.get(sym.st_name).?; |
| 3486 | } | 3402 | } |
| 3487 | | 3403 | |
| 3488 | /// Returns name of the global symbol at index. | 3404 | /// Returns pointer to the global entry for `name` if one exists. |
| 3489 | pub fn getGlobalName(self: *const Elf, index: u32) []const u8 { | 3405 | pub fn getGlobalPtr(self: *Elf, name: []const u8) ?*u32 { |
| 3490 | const sym = self.global_symbols.items[index]; | 3406 | const global_index = self.resolver.get(name) orelse return null; |
| 3491 | return self.strtab.get(sym.st_name).?; | 3407 | return &self.globals.items[global_index]; |
| | 3408 | } |
| | 3409 | |
| | 3410 | /// Returns the global entry for `name` if one exists. |
| | 3411 | pub fn getGlobal(self: *const Elf, name: []const u8) ?u32 { |
| | 3412 | const global_index = self.resolver.get(name) orelse return null; |
| | 3413 | return self.globals.items[global_index]; |
| | 3414 | } |
| | 3415 | |
| | 3416 | /// Returns the index of the global entry for `name` if one exists. |
| | 3417 | pub fn getGlobalIndex(self: *const Elf, name: []const u8) ?u32 { |
| | 3418 | return self.resolver.get(name); |
| | 3419 | } |
| | 3420 | |
| | 3421 | /// Returns global entry at `index`. |
| | 3422 | pub fn getGlobalByIndex(self: *const Elf, index: u32) u32 { |
| | 3423 | assert(index < self.globals.items.len); |
| | 3424 | return self.globals.items[index]; |
| | 3425 | } |
| | 3426 | |
| | 3427 | const GetOrPutGlobalPtrResult = struct { |
| | 3428 | found_existing: bool, |
| | 3429 | value_ptr: *u32, |
| | 3430 | }; |
| | 3431 | |
| | 3432 | /// Return pointer to the global entry for `name` if one exists. |
| | 3433 | /// Puts a new global entry for `name` if one doesn't exist, and |
| | 3434 | /// returns a pointer to it. |
| | 3435 | pub fn getOrPutGlobalPtr(self: *Elf, name: []const u8) !GetOrPutGlobalPtrResult { |
| | 3436 | if (self.getGlobalPtr(name)) |ptr| { |
| | 3437 | return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr }; |
| | 3438 | } |
| | 3439 | const gpa = self.base.allocator; |
| | 3440 | const global_index = try self.allocateGlobal(); |
| | 3441 | const global_name = try gpa.dupe(u8, name); |
| | 3442 | _ = try self.resolver.put(gpa, global_name, global_index); |
| | 3443 | const ptr = &self.globals.items[global_index]; |
| | 3444 | return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; |
| 3492 | } | 3445 | } |
| 3493 | | 3446 | |
| 3494 | pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom { | 3447 | pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom { |
| ... | @@ -3506,3 +3459,108 @@ pub fn getAtomPtr(self: *Elf, atom_index: Atom.Index) *Atom { | ... | @@ -3506,3 +3459,108 @@ pub fn getAtomPtr(self: *Elf, atom_index: Atom.Index) *Atom { |
| 3506 | pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index { | 3459 | pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index { |
| 3507 | return self.atom_by_index_table.get(sym_index); | 3460 | return self.atom_by_index_table.get(sym_index); |
| 3508 | } | 3461 | } |
| | 3462 | |
| | 3463 | pub const null_sym = elf.Elf64_Sym{ |
| | 3464 | .st_name = 0, |
| | 3465 | .st_info = 0, |
| | 3466 | .st_other = 0, |
| | 3467 | .st_shndx = 0, |
| | 3468 | .st_value = 0, |
| | 3469 | .st_size = 0, |
| | 3470 | }; |
| | 3471 | |
| | 3472 | const default_entry_addr = 0x8000000; |
| | 3473 | |
| | 3474 | pub const base_tag: File.Tag = .elf; |
| | 3475 | |
| | 3476 | const Section = struct { |
| | 3477 | shdr: elf.Elf64_Shdr, |
| | 3478 | phdr_index: u16, |
| | 3479 | |
| | 3480 | /// Index of the last allocated atom in this section. |
| | 3481 | last_atom_index: ?Atom.Index = null, |
| | 3482 | |
| | 3483 | /// A list of atoms that have surplus capacity. This list can have false |
| | 3484 | /// positives, as functions grow and shrink over time, only sometimes being added |
| | 3485 | /// or removed from the freelist. |
| | 3486 | /// |
| | 3487 | /// An atom has surplus capacity when its overcapacity value is greater than |
| | 3488 | /// padToIdeal(minimum_atom_size). That is, when it has so |
| | 3489 | /// much extra capacity, that we could fit a small new symbol in it, itself with |
| | 3490 | /// ideal_capacity or more. |
| | 3491 | /// |
| | 3492 | /// Ideal capacity is defined by size + (size / ideal_factor) |
| | 3493 | /// |
| | 3494 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that |
| | 3495 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| | 3496 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| | 3497 | /// by 1 byte. It will then have -1 overcapacity. |
| | 3498 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| | 3499 | }; |
| | 3500 | |
| | 3501 | const LazySymbolMetadata = struct { |
| | 3502 | const State = enum { unused, pending_flush, flushed }; |
| | 3503 | text_atom: Atom.Index = undefined, |
| | 3504 | rodata_atom: Atom.Index = undefined, |
| | 3505 | text_state: State = .unused, |
| | 3506 | rodata_state: State = .unused, |
| | 3507 | }; |
| | 3508 | |
| | 3509 | const DeclMetadata = struct { |
| | 3510 | atom: Atom.Index, |
| | 3511 | shdr: u16, |
| | 3512 | /// A list of all exports aliases of this Decl. |
| | 3513 | exports: std.ArrayListUnmanaged(u32) = .{}, |
| | 3514 | |
| | 3515 | fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 { |
| | 3516 | for (m.exports.items) |exp| { |
| | 3517 | if (mem.eql(u8, name, elf_file.getSymbolName(exp))) return exp; |
| | 3518 | } |
| | 3519 | return null; |
| | 3520 | } |
| | 3521 | |
| | 3522 | fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { |
| | 3523 | for (m.exports.items) |*exp| { |
| | 3524 | if (mem.eql(u8, name, elf_file.getSymbolName(exp.*))) return exp; |
| | 3525 | } |
| | 3526 | return null; |
| | 3527 | } |
| | 3528 | }; |
| | 3529 | |
| | 3530 | const Elf = @This(); |
| | 3531 | |
| | 3532 | const std = @import("std"); |
| | 3533 | const build_options = @import("build_options"); |
| | 3534 | const builtin = @import("builtin"); |
| | 3535 | const assert = std.debug.assert; |
| | 3536 | const elf = std.elf; |
| | 3537 | const fs = std.fs; |
| | 3538 | const log = std.log.scoped(.link); |
| | 3539 | const math = std.math; |
| | 3540 | const mem = std.mem; |
| | 3541 | |
| | 3542 | const codegen = @import("../codegen.zig"); |
| | 3543 | const glibc = @import("../glibc.zig"); |
| | 3544 | const link = @import("../link.zig"); |
| | 3545 | const lldMain = @import("../main.zig").lldMain; |
| | 3546 | const musl = @import("../musl.zig"); |
| | 3547 | const target_util = @import("../target.zig"); |
| | 3548 | const trace = @import("../tracy.zig").trace; |
| | 3549 | |
| | 3550 | const Air = @import("../Air.zig"); |
| | 3551 | const Allocator = std.mem.Allocator; |
| | 3552 | pub const Atom = @import("Elf/Atom.zig"); |
| | 3553 | const Cache = std.Build.Cache; |
| | 3554 | const Compilation = @import("../Compilation.zig"); |
| | 3555 | const Dwarf = @import("Dwarf.zig"); |
| | 3556 | const File = link.File; |
| | 3557 | const Liveness = @import("../Liveness.zig"); |
| | 3558 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| | 3559 | const Module = @import("../Module.zig"); |
| | 3560 | const InternPool = @import("../InternPool.zig"); |
| | 3561 | const Package = @import("../Package.zig"); |
| | 3562 | const StringTable = @import("strtab.zig").StringTable; |
| | 3563 | const TableSection = @import("table_section.zig").TableSection; |
| | 3564 | const Type = @import("../type.zig").Type; |
| | 3565 | const TypedValue = @import("../TypedValue.zig"); |
| | 3566 | const Value = @import("../value.zig").Value; |