| ... | ... | @@ -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 | 1 | base: File, |
| 98 | 2 | dwarf: ?Dwarf = null, |
| 99 | 3 | |
| ... | ... | @@ -151,11 +55,13 @@ strtab_section_index: ?u16 = null, |
| 151 | 55 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and |
| 152 | 56 | /// write them at the end. These are only the local symbols. The length of this array |
| 153 | 57 | /// is the value used for sh_info in the .symtab section. |
| 154 | | local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 155 | | global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 58 | locals: 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) = .{}, |
| 158 | | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 63 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 64 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 159 | 65 | |
| 160 | 66 | got_table: TableSection(u32) = .{}, |
| 161 | 67 | |
| ... | ... | @@ -247,14 +153,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 247 | 153 | self.shdr_table_dirty = true; |
| 248 | 154 | |
| 249 | 155 | // Index 0 is always a null symbol. |
| 250 | | try self.local_symbols.append(allocator, .{ |
| 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 | | }); |
| 156 | try self.locals.append(allocator, null_sym); |
| 258 | 157 | |
| 259 | 158 | // There must always be a null section in index 0 |
| 260 | 159 | try self.sections.append(allocator, .{ |
| ... | ... | @@ -329,11 +228,20 @@ pub fn deinit(self: *Elf) void { |
| 329 | 228 | self.program_headers.deinit(gpa); |
| 330 | 229 | self.shstrtab.deinit(gpa); |
| 331 | 230 | self.strtab.deinit(gpa); |
| 332 | | self.local_symbols.deinit(gpa); |
| 333 | | self.global_symbols.deinit(gpa); |
| 334 | | self.global_symbol_free_list.deinit(gpa); |
| 335 | | self.local_symbol_free_list.deinit(gpa); |
| 231 | self.locals.deinit(gpa); |
| 232 | self.globals.deinit(gpa); |
| 233 | self.globals_free_list.deinit(gpa); |
| 234 | self.locals_free_list.deinit(gpa); |
| 336 | 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 | 247 | var it = self.decls.iterator(); |
| ... | ... | @@ -743,7 +651,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 743 | 651 | .sh_size = file_size, |
| 744 | 652 | // The section header index of the associated string table. |
| 745 | 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 | 655 | .sh_addralign = min_align, |
| 748 | 656 | .sh_entsize = each_size, |
| 749 | 657 | }, |
| ... | ... | @@ -908,7 +816,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 908 | 816 | |
| 909 | 817 | { |
| 910 | 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 | 820 | @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); |
| 913 | 821 | } |
| 914 | 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 | 1017 | log.debug("relocating '{?s}'", .{self.strtab.get(source_sym.st_name)}); |
| 1110 | 1018 | |
| 1111 | 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 | 1021 | const target_vaddr = target_sym.st_value + reloc.addend; |
| 1114 | 1022 | |
| 1115 | 1023 | if (target_vaddr == reloc.prev_vaddr) continue; |
| ... | ... | @@ -2219,22 +2127,14 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { |
| 2219 | 2127 | } |
| 2220 | 2128 | |
| 2221 | 2129 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2222 | | const local_sym_index = atom.getSymbolIndex().?; |
| 2223 | | |
| 2224 | | log.debug("adding %{d} to local symbols free list", .{local_sym_index}); |
| 2225 | | self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; |
| 2226 | | self.local_symbols.items[local_sym_index] = .{ |
| 2227 | | .st_name = 0, |
| 2228 | | .st_info = 0, |
| 2229 | | .st_other = 0, |
| 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); |
| 2130 | const sym_index = atom.getSymbolIndex().?; |
| 2131 | |
| 2132 | log.debug("adding %{d} to local symbols free list", .{sym_index}); |
| 2133 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 2134 | self.locals.items[sym_index] = null_sym; |
| 2135 | _ = self.atom_by_index_table.remove(sym_index); |
| 2136 | self.getAtomPtr(atom_index).sym_index = 0; |
| 2137 | self.got_table.freeEntry(gpa, sym_index); |
| 2238 | 2138 | } |
| 2239 | 2139 | |
| 2240 | 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 | 2156 | const gpa = self.base.allocator; |
| 2257 | 2157 | const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len)); |
| 2258 | 2158 | const atom = try self.atoms.addOne(gpa); |
| 2259 | | const local_sym_index = try self.allocateLocalSymbol(); |
| 2260 | | try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index); |
| 2159 | const sym_index = try self.allocateSymbol(); |
| 2160 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 2261 | 2161 | atom.* = .{ |
| 2262 | | .local_sym_index = local_sym_index, |
| 2162 | .sym_index = sym_index, |
| 2263 | 2163 | .prev_index = null, |
| 2264 | 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 | 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 | 2289 | return vaddr; |
| 2390 | 2290 | } |
| 2391 | 2291 | |
| 2392 | | pub fn allocateLocalSymbol(self: *Elf) !u32 { |
| 2393 | | try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); |
| 2394 | | |
| 2292 | pub fn allocateSymbol(self: *Elf) !u32 { |
| 2293 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 2395 | 2294 | const index = blk: { |
| 2396 | | if (self.local_symbol_free_list.popOrNull()) |index| { |
| 2295 | if (self.locals_free_list.popOrNull()) |index| { |
| 2397 | 2296 | log.debug(" (reusing symbol index {d})", .{index}); |
| 2398 | 2297 | break :blk index; |
| 2399 | 2298 | } else { |
| 2400 | | log.debug(" (allocating symbol index {d})", .{self.local_symbols.items.len}); |
| 2401 | | const index = @as(u32, @intCast(self.local_symbols.items.len)); |
| 2402 | | _ = self.local_symbols.addOneAssumeCapacity(); |
| 2299 | log.debug(" (allocating symbol index {d})", .{self.locals.items.len}); |
| 2300 | const index = @as(u32, @intCast(self.locals.items.len)); |
| 2301 | _ = self.locals.addOneAssumeCapacity(); |
| 2403 | 2302 | break :blk index; |
| 2404 | 2303 | } |
| 2405 | 2304 | }; |
| 2406 | | |
| 2407 | | self.local_symbols.items[index] = .{ |
| 2305 | self.locals.items[index] = .{ |
| 2408 | 2306 | .st_name = 0, |
| 2409 | 2307 | .st_info = 0, |
| 2410 | 2308 | .st_other = 0, |
| ... | ... | @@ -2412,7 +2310,23 @@ pub fn allocateLocalSymbol(self: *Elf) !u32 { |
| 2412 | 2310 | .st_value = 0, |
| 2413 | 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 | 2330 | return index; |
| 2417 | 2331 | } |
| 2418 | 2332 | |
| ... | ... | @@ -2896,8 +2810,6 @@ pub fn updateDeclExports( |
| 2896 | 2810 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 2897 | 2811 | const shdr_index = decl_metadata.shdr; |
| 2898 | 2812 | |
| 2899 | | try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); |
| 2900 | | |
| 2901 | 2813 | for (exports) |exp| { |
| 2902 | 2814 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); |
| 2903 | 2815 | if (exp.opts.section.unwrap()) |section_name| { |
| ... | ... | @@ -2905,7 +2817,7 @@ pub fn updateDeclExports( |
| 2905 | 2817 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2906 | 2818 | mod.failed_exports.putAssumeCapacityNoClobber( |
| 2907 | 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 | 2822 | continue; |
| 2911 | 2823 | } |
| ... | ... | @@ -2924,37 +2836,30 @@ pub fn updateDeclExports( |
| 2924 | 2836 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2925 | 2837 | mod.failed_exports.putAssumeCapacityNoClobber( |
| 2926 | 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 | 2841 | continue; |
| 2930 | 2842 | }, |
| 2931 | 2843 | }; |
| 2932 | 2844 | const stt_bits: u8 = @as(u4, @truncate(decl_sym.st_info)); |
| 2933 | | if (decl_metadata.getExport(self, exp_name)) |i| { |
| 2934 | | const sym = &self.global_symbols.items[i]; |
| 2935 | | sym.* = .{ |
| 2936 | | .st_name = try self.strtab.insert(gpa, exp_name), |
| 2937 | | .st_info = (stb_bits << 4) | stt_bits, |
| 2938 | | .st_other = 0, |
| 2939 | | .st_shndx = shdr_index, |
| 2940 | | .st_value = decl_sym.st_value, |
| 2941 | | .st_size = decl_sym.st_size, |
| 2942 | | }; |
| 2943 | | } else { |
| 2944 | | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { |
| 2945 | | _ = self.global_symbols.addOneAssumeCapacity(); |
| 2946 | | break :blk self.global_symbols.items.len - 1; |
| 2947 | | }; |
| 2948 | | try decl_metadata.exports.append(gpa, @as(u32, @intCast(i))); |
| 2949 | | self.global_symbols.items[i] = .{ |
| 2950 | | .st_name = try self.strtab.insert(gpa, exp_name), |
| 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 | | } |
| 2845 | |
| 2846 | const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { |
| 2847 | const sym_index = try self.allocateSymbol(); |
| 2848 | try decl_metadata.exports.append(gpa, sym_index); |
| 2849 | break :blk sym_index; |
| 2850 | }; |
| 2851 | const sym = self.getSymbolPtr(sym_index); |
| 2852 | sym.* = .{ |
| 2853 | .st_name = try self.strtab.insert(gpa, exp_name), |
| 2854 | .st_info = (stb_bits << 4) | stt_bits, |
| 2855 | .st_other = 0, |
| 2856 | .st_shndx = shdr_index, |
| 2857 | .st_value = decl_sym.st_value, |
| 2858 | .st_size = decl_sym.st_size, |
| 2859 | }; |
| 2860 | const sym_name = self.getSymbolName(sym_index); |
| 2861 | const gop = try self.getOrPutGlobalPtr(sym_name); |
| 2862 | gop.value_ptr.* = sym_index; |
| 2958 | 2863 | } |
| 2959 | 2864 | } |
| 2960 | 2865 | |
| ... | ... | @@ -2981,10 +2886,20 @@ pub fn deleteDeclExport( |
| 2981 | 2886 | ) void { |
| 2982 | 2887 | if (self.llvm_object) |_| return; |
| 2983 | 2888 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 2889 | const gpa = self.base.allocator; |
| 2984 | 2890 | const mod = self.base.options.module.?; |
| 2985 | | const sym_index = metadata.getExportPtr(self, mod.intern_pool.stringToSlice(name)) orelse return; |
| 2986 | | self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; |
| 2987 | | self.global_symbols.items[sym_index.*].st_info = 0; |
| 2891 | const exp_name = mod.intern_pool.stringToSlice(name); |
| 2892 | const sym_index = metadata.getExportPtr(self, exp_name) orelse return; |
| 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 | 2903 | sym_index.* = 0; |
| 2989 | 2904 | } |
| 2990 | 2905 | |
| ... | ... | @@ -3110,10 +3025,10 @@ fn writeSymbols(self: *Elf) !void { |
| 3110 | 3025 | }; |
| 3111 | 3026 | |
| 3112 | 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 | 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 | 3032 | const needed_size = nsyms * sym_size; |
| 3118 | 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 | 3039 | const buf = try gpa.alloc(elf.Elf32_Sym, nsyms); |
| 3125 | 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 | 3043 | elf32SymFromSym(local, sym); |
| 3129 | 3044 | if (foreign_endian) { |
| 3130 | 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| { |
| 3135 | | elf32SymFromSym(global, sym); |
| 3049 | for (buf[self.locals.items.len..], self.globals.items) |*sym, global| { |
| 3050 | elf32SymFromSym(self.getSymbol(global), sym); |
| 3136 | 3051 | if (foreign_endian) { |
| 3137 | 3052 | mem.byteSwapAllFields(elf.Elf32_Sym, sym); |
| 3138 | 3053 | } |
| ... | ... | @@ -3142,15 +3057,15 @@ fn writeSymbols(self: *Elf) !void { |
| 3142 | 3057 | .p64 => { |
| 3143 | 3058 | const buf = try gpa.alloc(elf.Elf64_Sym, nsyms); |
| 3144 | 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 | 3061 | sym.* = local; |
| 3147 | 3062 | if (foreign_endian) { |
| 3148 | 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| { |
| 3153 | | sym.* = global; |
| 3067 | for (buf[self.locals.items.len..], self.globals.items) |*sym, global| { |
| 3068 | sym.* = self.getSymbol(global); |
| 3154 | 3069 | if (foreign_endian) { |
| 3155 | 3070 | mem.byteSwapAllFields(elf.Elf64_Sym, sym); |
| 3156 | 3071 | } |
| ... | ... | @@ -3450,11 +3365,12 @@ const CsuObjects = struct { |
| 3450 | 3365 | |
| 3451 | 3366 | fn logSymtab(self: Elf) void { |
| 3452 | 3367 | log.debug("locals:", .{}); |
| 3453 | | for (self.local_symbols.items, 0..) |sym, id| { |
| 3368 | for (self.locals.items, 0..) |sym, id| { |
| 3454 | 3369 | log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.strtab.get(sym.st_name), sym.st_value, sym.st_shndx }); |
| 3455 | 3370 | } |
| 3456 | 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 | 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 | 3387 | |
| 3472 | 3388 | /// Returns pointer-to-symbol described at sym_index. |
| 3473 | 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 | 3393 | /// Returns symbol at sym_index. |
| 3478 | 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 | 3398 | /// Returns name of the symbol at sym_index. |
| 3483 | 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 | 3401 | return self.strtab.get(sym.st_name).?; |
| 3486 | 3402 | } |
| 3487 | 3403 | |
| 3488 | | /// Returns name of the global symbol at index. |
| 3489 | | pub fn getGlobalName(self: *const Elf, index: u32) []const u8 { |
| 3490 | | const sym = self.global_symbols.items[index]; |
| 3491 | | return self.strtab.get(sym.st_name).?; |
| 3404 | /// Returns pointer to the global entry for `name` if one exists. |
| 3405 | pub fn getGlobalPtr(self: *Elf, name: []const u8) ?*u32 { |
| 3406 | const global_index = self.resolver.get(name) orelse return null; |
| 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 | 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 | 3459 | pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index { |
| 3507 | 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; |