authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-02 17:23:49+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-03 08:32:28+02:00
log009a349779186548480823140dd1f8758d600221
tree10a79ff337318e726608f611360fee1b040400f8
parente265dc61e651d67bbfb3be675ff132df865902ef

elf: add global symbol resolver


2 files changed, 262 insertions(+), 204 deletions(-)

src/link/Elf.zig+251-193
...@@ -1,99 +1,3 @@...@@ -1,99 +1,3 @@
1const Elf = @This();
2
3const std = @import("std");
4const build_options = @import("build_options");
5const builtin = @import("builtin");
6const assert = std.debug.assert;
7const elf = std.elf;
8const fs = std.fs;
9const log = std.log.scoped(.link);
10const math = std.math;
11const mem = std.mem;
12
13const codegen = @import("../codegen.zig");
14const glibc = @import("../glibc.zig");
15const link = @import("../link.zig");
16const lldMain = @import("../main.zig").lldMain;
17const musl = @import("../musl.zig");
18const target_util = @import("../target.zig");
19const trace = @import("../tracy.zig").trace;
20
21const Air = @import("../Air.zig");
22const Allocator = std.mem.Allocator;
23pub const Atom = @import("Elf/Atom.zig");
24const Cache = std.Build.Cache;
25const Compilation = @import("../Compilation.zig");
26const Dwarf = @import("Dwarf.zig");
27const File = link.File;
28const Liveness = @import("../Liveness.zig");
29const LlvmObject = @import("../codegen/llvm.zig").Object;
30const Module = @import("../Module.zig");
31const InternPool = @import("../InternPool.zig");
32const Package = @import("../Package.zig");
33const StringTable = @import("strtab.zig").StringTable;
34const TableSection = @import("table_section.zig").TableSection;
35const Type = @import("../type.zig").Type;
36const TypedValue = @import("../TypedValue.zig");
37const Value = @import("../value.zig").Value;
38
39const default_entry_addr = 0x8000000;
40
41pub const base_tag: File.Tag = .elf;
42
43const 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
68const 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
76const 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
97base: File,1base: File,
98dwarf: ?Dwarf = null,2dwarf: ?Dwarf = null,
993
...@@ -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 and55/// 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 array56/// 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.
154local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},58locals: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
155global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},59globals: std.ArrayListUnmanaged(u32) = .{},
60resolver: std.StringHashMapUnmanaged(u32) = .{},
61unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
15662
157local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},63locals_free_list: std.ArrayListUnmanaged(u32) = .{},
158global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},64globals_free_list: std.ArrayListUnmanaged(u32) = .{},
15965
160got_table: TableSection(u32) = .{},66got_table: TableSection(u32) = .{},
16167
...@@ -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;
248154
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 });
258157
259 // There must always be a null section in index 0158 // 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 }
337245
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 {
908816
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)});
11101018
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;
11141022
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 }
22202128
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().?;
22232131
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}
22392139
2240fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {2140fn 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}
22692169
...@@ -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}
23912291
2392pub fn allocateLocalSymbol(self: *Elf) !u32 {2292pub 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 };
24062305 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}
24152315
2316fn 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}
24182332
...@@ -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;
28982812
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}
29602865
...@@ -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}
29902905
...@@ -3110,10 +3025,10 @@ fn writeSymbols(self: *Elf) !void {...@@ -3110,10 +3025,10 @@ fn writeSymbols(self: *Elf) !void {
3110 };3025 };
31113026
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);
31153030
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);
31193034
...@@ -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);
31263041
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 }
31333048
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 }
31513066
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 {
34503365
3451fn logSymtab(self: Elf) void {3366fn 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 {
34713387
3472/// Returns pointer-to-symbol described at sym_index.3388/// Returns pointer-to-symbol described at sym_index.
3473pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym {3389pub 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}
34763392
3477/// Returns symbol at sym_index.3393/// Returns symbol at sym_index.
3478pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym {3394pub 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}
34813397
3482/// Returns name of the symbol at sym_index.3398/// Returns name of the symbol at sym_index.
3483pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 {3399pub 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}
34873403
3488/// Returns name of the global symbol at index.3404/// Returns pointer to the global entry for `name` if one exists.
3489pub fn getGlobalName(self: *const Elf, index: u32) []const u8 {3405pub 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.
3411pub 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.
3417pub fn getGlobalIndex(self: *const Elf, name: []const u8) ?u32 {
3418 return self.resolver.get(name);
3419}
3420
3421/// Returns global entry at `index`.
3422pub fn getGlobalByIndex(self: *const Elf, index: u32) u32 {
3423 assert(index < self.globals.items.len);
3424 return self.globals.items[index];
3425}
3426
3427const 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.
3435pub 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}
34933446
3494pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom {3447pub 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 {
3506pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index {3459pub 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
3463pub 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
3472const default_entry_addr = 0x8000000;
3473
3474pub const base_tag: File.Tag = .elf;
3475
3476const 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
3501const 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
3509const 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
3530const Elf = @This();
3531
3532const std = @import("std");
3533const build_options = @import("build_options");
3534const builtin = @import("builtin");
3535const assert = std.debug.assert;
3536const elf = std.elf;
3537const fs = std.fs;
3538const log = std.log.scoped(.link);
3539const math = std.math;
3540const mem = std.mem;
3541
3542const codegen = @import("../codegen.zig");
3543const glibc = @import("../glibc.zig");
3544const link = @import("../link.zig");
3545const lldMain = @import("../main.zig").lldMain;
3546const musl = @import("../musl.zig");
3547const target_util = @import("../target.zig");
3548const trace = @import("../tracy.zig").trace;
3549
3550const Air = @import("../Air.zig");
3551const Allocator = std.mem.Allocator;
3552pub const Atom = @import("Elf/Atom.zig");
3553const Cache = std.Build.Cache;
3554const Compilation = @import("../Compilation.zig");
3555const Dwarf = @import("Dwarf.zig");
3556const File = link.File;
3557const Liveness = @import("../Liveness.zig");
3558const LlvmObject = @import("../codegen/llvm.zig").Object;
3559const Module = @import("../Module.zig");
3560const InternPool = @import("../InternPool.zig");
3561const Package = @import("../Package.zig");
3562const StringTable = @import("strtab.zig").StringTable;
3563const TableSection = @import("table_section.zig").TableSection;
3564const Type = @import("../type.zig").Type;
3565const TypedValue = @import("../TypedValue.zig");
3566const Value = @import("../value.zig").Value;
src/link/Elf/Atom.zig+11-11
...@@ -1,18 +1,10 @@...@@ -1,18 +1,10 @@
1const Atom = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const elf = std.elf;
6
7const Elf = @import("../Elf.zig");
8
9/// Each decl always gets a local symbol with the fully qualified name.1/// Each decl always gets a local symbol with the fully qualified name.
10/// The vaddr and size are found here directly.2/// The vaddr and size are found here directly.
11/// The file offset is found by computing the vaddr offset from the section vaddr3/// The file offset is found by computing the vaddr offset from the section vaddr
12/// the symbol references, and adding that to the file offset of the section.4/// the symbol references, and adding that to the file offset of the section.
13/// If this field is 0, it means the codegen size = 0 and there is no symbol or5/// If this field is 0, it means the codegen size = 0 and there is no symbol or
14/// offset table entry.6/// offset table entry.
15local_sym_index: u32,7sym_index: u32,
168
17/// Points to the previous and next neighbors, based on the `text_offset`.9/// Points to the previous and next neighbors, based on the `text_offset`.
18/// This can be used to find, for example, the capacity of this `TextBlock`.10/// This can be used to find, for example, the capacity of this `TextBlock`.
...@@ -29,8 +21,8 @@ pub const Reloc = struct {...@@ -29,8 +21,8 @@ pub const Reloc = struct {
29};21};
3022
31pub fn getSymbolIndex(self: Atom) ?u32 {23pub fn getSymbolIndex(self: Atom) ?u32 {
32 if (self.local_sym_index == 0) return null;24 if (self.sym_index == 0) return null;
33 return self.local_sym_index;25 return self.sym_index;
34}26}
3527
36pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {28pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {
...@@ -106,3 +98,11 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {...@@ -106,3 +98,11 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
106 var removed_relocs = elf_file.relocs.fetchRemove(atom_index);98 var removed_relocs = elf_file.relocs.fetchRemove(atom_index);
107 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);99 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
108}100}
101
102const Atom = @This();
103
104const std = @import("std");
105const assert = std.debug.assert;
106const elf = std.elf;
107
108const Elf = @import("../Elf.zig");