authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-13 21:32:54+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:05+02:00
log85d451f96cd8f2854fa6a092625b8a2f3c474a73
tree0c001659b2021fe860cb982f137aacf271a5e668
parent7be983ac9217a596b7f35e7ef4c49fda0270e10b

elf: re-enable self-hosted backends


4 files changed, 110 insertions(+), 21 deletions(-)

src/link/Elf.zig+62-6
...@@ -762,6 +762,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -762,6 +762,7 @@ pub fn initMetadata(self: *Elf) !void {
762 .name = ".zig.got",762 .name = ".zig.got",
763 .phdr_index = self.phdr_zig_got_index.?,763 .phdr_index = self.phdr_zig_got_index.?,
764 .alignment = ptr_size,764 .alignment = ptr_size,
765 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
765 });766 });
766 }767 }
767768
...@@ -785,7 +786,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -785,7 +786,7 @@ pub fn initMetadata(self: *Elf) !void {
785786
786 if (self.zig_bss_section_index == null) {787 if (self.zig_bss_section_index == null) {
787 self.zig_bss_section_index = try self.allocateAllocSection(.{788 self.zig_bss_section_index = try self.allocateAllocSection(.{
788 .name = ".bss.zig",789 .name = ".zig.bss",
789 .phdr_index = self.phdr_zig_load_zerofill_index.?,790 .phdr_index = self.phdr_zig_load_zerofill_index.?,
790 .alignment = ptr_size,791 .alignment = ptr_size,
791 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,792 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
...@@ -1558,7 +1559,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1558,7 +1559,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1558 for (zig_module.atoms.items) |atom_index| {1559 for (zig_module.atoms.items) |atom_index| {
1559 const atom_ptr = self.atom(atom_index) orelse continue;1560 const atom_ptr = self.atom(atom_index) orelse continue;
1560 if (!atom_ptr.flags.alive) continue;1561 if (!atom_ptr.flags.alive) continue;
1561 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];1562 const out_shndx = atom_ptr.outputShndx() orelse continue;
1563 const shdr = &self.shdrs.items[out_shndx];
1562 if (shdr.sh_type == elf.SHT_NOBITS) continue;1564 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1563 const code = try zig_module.codeAlloc(self, atom_index);1565 const code = try zig_module.codeAlloc(self, atom_index);
1564 defer gpa.free(code);1566 defer gpa.free(code);
...@@ -3744,6 +3746,9 @@ fn initSections(self: *Elf) !void {...@@ -3744,6 +3746,9 @@ fn initSections(self: *Elf) !void {
3744 const needs_rela_dyn = blk: {3746 const needs_rela_dyn = blk: {
3745 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or3747 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
3746 self.copy_rel.symbols.items.len > 0) break :blk true;3748 self.copy_rel.symbols.items.len > 0) break :blk true;
3749 if (self.zig_module_index) |index| {
3750 if (self.file(index).?.zig_module.num_dynrelocs > 0) break :blk true;
3751 }
3747 for (self.objects.items) |index| {3752 for (self.objects.items) |index| {
3748 if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;3753 if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;
3749 }3754 }
...@@ -4243,6 +4248,33 @@ fn sortSections(self: *Elf) !void {...@@ -4243,6 +4248,33 @@ fn sortSections(self: *Elf) !void {
4243 shdr.sh_link = self.dynsymtab_section_index.?;4248 shdr.sh_link = self.dynsymtab_section_index.?;
4244 shdr.sh_info = self.plt_section_index.?;4249 shdr.sh_info = self.plt_section_index.?;
4245 }4250 }
4251
4252 if (self.zig_module_index) |index| {
4253 const zig_module = self.file(index).?.zig_module;
4254 for (zig_module.atoms.items) |atom_index| {
4255 const atom_ptr = self.atom(atom_index) orelse continue;
4256 if (!atom_ptr.flags.alive) continue;
4257 const out_shndx = atom_ptr.outputShndx() orelse continue;
4258 atom_ptr.output_section_index = backlinks[out_shndx];
4259 }
4260
4261 for (zig_module.locals()) |local_index| {
4262 const local = self.symbol(local_index);
4263 const atom_ptr = local.atom(self) orelse continue;
4264 if (!atom_ptr.flags.alive) continue;
4265 const out_shndx = local.outputShndx() orelse continue;
4266 local.output_section_index = backlinks[out_shndx];
4267 }
4268
4269 for (zig_module.globals()) |global_index| {
4270 const global = self.symbol(global_index);
4271 const atom_ptr = global.atom(self) orelse continue;
4272 if (!atom_ptr.flags.alive) continue;
4273 if (global.file(self).?.index() != index) continue;
4274 const out_shndx = global.outputShndx() orelse continue;
4275 global.output_section_index = backlinks[out_shndx];
4276 }
4277 }
4246}4278}
42474279
4248fn updateSectionSizes(self: *Elf) !void {4280fn updateSectionSizes(self: *Elf) !void {
...@@ -4286,6 +4318,9 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4286,6 +4318,9 @@ fn updateSectionSizes(self: *Elf) !void {
42864318
4287 if (self.rela_dyn_section_index) |shndx| {4319 if (self.rela_dyn_section_index) |shndx| {
4288 var num = self.got.numRela(self) + self.copy_rel.numRela();4320 var num = self.got.numRela(self) + self.copy_rel.numRela();
4321 if (self.zig_module_index) |index| {
4322 num += self.file(index).?.zig_module.num_dynrelocs;
4323 }
4289 for (self.objects.items) |index| {4324 for (self.objects.items) |index| {
4290 num += self.file(index).?.object.num_dynrelocs;4325 num += self.file(index).?.object.num_dynrelocs;
4291 }4326 }
...@@ -4373,9 +4408,10 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {...@@ -4373,9 +4408,10 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
4373fn calcNumberOfSegments(self: *Elf) usize {4408fn calcNumberOfSegments(self: *Elf) usize {
4374 var count: usize = 0;4409 var count: usize = 0;
4375 var flags: u64 = 0;4410 var flags: u64 = 0;
4376 for (self.shdrs.items) |shdr| {4411 for (self.shdrs.items, 0..) |shdr, shndx| {
4377 if (shdr.sh_type == elf.SHT_NULL) continue;4412 if (shdr.sh_type == elf.SHT_NULL) continue;
4378 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;4413 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4414 if (self.isZigSection(@intCast(shndx))) continue;
4379 if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1;4415 if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1;
4380 flags = shdrToPhdrFlags(shdr.sh_flags);4416 flags = shdrToPhdrFlags(shdr.sh_flags);
4381 }4417 }
...@@ -4474,7 +4510,10 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4474,7 +4510,10 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4474 }4510 }
4475 }4511 }
4476 }4512 }
4477 covers[nphdrs - 1].len = shndx - covers[nphdrs - 1].start;4513
4514 if (nphdrs > 0) {
4515 covers[nphdrs - 1].len = shndx - covers[nphdrs - 1].start;
4516 }
44784517
4479 // Now we can proceed with allocating the sections in virtual memory.4518 // Now we can proceed with allocating the sections in virtual memory.
4480 // As the base address we take the end address of the PHDR table.4519 // As the base address we take the end address of the PHDR table.
...@@ -4647,6 +4686,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4647,6 +4686,7 @@ fn writeAtoms(self: *Elf) !void {
4647 undefs.deinit();4686 undefs.deinit();
4648 }4687 }
46494688
4689 // TODO iterate over `output_sections` directly
4650 for (self.shdrs.items, 0..) |shdr, shndx| {4690 for (self.shdrs.items, 0..) |shdr, shndx| {
4651 if (shdr.sh_type == elf.SHT_NULL) continue;4691 if (shdr.sh_type == elf.SHT_NULL) continue;
4652 if (shdr.sh_type == elf.SHT_NOBITS) continue;4692 if (shdr.sh_type == elf.SHT_NOBITS) continue;
...@@ -5830,7 +5870,10 @@ fn fmtDumpState(...@@ -5830,7 +5870,10 @@ fn fmtDumpState(
5830 if (self.zig_module_index) |index| {5870 if (self.zig_module_index) |index| {
5831 const zig_module = self.file(index).?.zig_module;5871 const zig_module = self.file(index).?.zig_module;
5832 try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path });5872 try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path });
5833 try writer.print("{}\n", .{zig_module.fmtSymtab(self)});5873 try writer.print("{}{}\n", .{
5874 zig_module.fmtAtoms(self),
5875 zig_module.fmtSymtab(self),
5876 });
5834 }5877 }
58355878
5836 for (self.objects.items) |index| {5879 for (self.objects.items) |index| {
...@@ -5872,7 +5915,7 @@ fn fmtDumpState(...@@ -5872,7 +5915,7 @@ fn fmtDumpState(
5872 self.fmtShdr(shdr),5915 self.fmtShdr(shdr),
5873 });5916 });
5874 }5917 }
5875 try writer.writeAll("Output phdrs\n");5918 try writer.writeAll("\nOutput phdrs\n");
5876 for (self.phdrs.items, 0..) |phdr, phndx| {5919 for (self.phdrs.items, 0..) |phdr, phndx| {
5877 try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) });5920 try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) });
5878 }5921 }
...@@ -5983,6 +6026,19 @@ pub const null_sym = elf.Elf64_Sym{...@@ -5983,6 +6026,19 @@ pub const null_sym = elf.Elf64_Sym{
5983 .st_size = 0,6026 .st_size = 0,
5984};6027};
59856028
6029pub const null_shdr = elf.Elf64_Shdr{
6030 .sh_name = 0,
6031 .sh_type = 0,
6032 .sh_flags = 0,
6033 .sh_addr = 0,
6034 .sh_offset = 0,
6035 .sh_size = 0,
6036 .sh_link = 0,
6037 .sh_info = 0,
6038 .sh_addralign = 0,
6039 .sh_entsize = 0,
6040};
6041
5986const SystemLib = struct {6042const SystemLib = struct {
5987 needed: bool = false,6043 needed: bool = false,
5988 path: []const u8,6044 path: []const u8,
src/link/Elf/Atom.zig+21-13
...@@ -50,8 +50,11 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {...@@ -50,8 +50,11 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
50}50}
5151
52pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {52pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
53 const object = self.file(elf_file).?.object;53 return switch (self.file(elf_file).?) {
54 return object.shdrs.items[self.input_section_index];54 .object => |x| x.shdrs.items[self.input_section_index],
55 .zig_module => |x| x.inputShdr(self.atom_index, elf_file),
56 else => unreachable,
57 };
55}58}
5659
57pub fn outputShndx(self: Atom) ?u16 {60pub fn outputShndx(self: Atom) ?u16 {
...@@ -199,7 +202,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -199,7 +202,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
199 _ = free_list.swapRemove(i);202 _ = free_list.swapRemove(i);
200 }203 }
201204
202 self.flags.allocated = true;205 self.flags.alive = true;
203}206}
204207
205pub fn shrink(self: *Atom, elf_file: *Elf) void {208pub fn shrink(self: *Atom, elf_file: *Elf) void {
...@@ -471,7 +474,11 @@ fn scanReloc(...@@ -471,7 +474,11 @@ fn scanReloc(
471 elf_file: *Elf,474 elf_file: *Elf,
472) error{OutOfMemory}!void {475) error{OutOfMemory}!void {
473 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;476 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
474 const object = self.file(elf_file).?.object;477 const num_dynrelocs = switch (self.file(elf_file).?) {
478 .linker_defined => unreachable,
479 .shared_object => unreachable,
480 inline else => |x| &x.num_dynrelocs,
481 };
475482
476 switch (action) {483 switch (action) {
477 .none => {},484 .none => {},
...@@ -500,7 +507,7 @@ fn scanReloc(...@@ -500,7 +507,7 @@ fn scanReloc(
500 try self.reportTextRelocError(symbol, rel, elf_file);507 try self.reportTextRelocError(symbol, rel, elf_file);
501 }508 }
502 }509 }
503 object.num_dynrelocs += 1;510 num_dynrelocs.* += 1;
504 } else {511 } else {
505 symbol.flags.needs_copy_rel = true;512 symbol.flags.needs_copy_rel = true;
506 }513 }
...@@ -517,7 +524,7 @@ fn scanReloc(...@@ -517,7 +524,7 @@ fn scanReloc(
517524
518 .dyn_cplt => {525 .dyn_cplt => {
519 if (is_writeable) {526 if (is_writeable) {
520 object.num_dynrelocs += 1;527 num_dynrelocs.* += 1;
521 } else {528 } else {
522 symbol.flags.needs_plt = true;529 symbol.flags.needs_plt = true;
523 symbol.flags.is_canonical = true;530 symbol.flags.is_canonical = true;
...@@ -532,7 +539,7 @@ fn scanReloc(...@@ -532,7 +539,7 @@ fn scanReloc(
532 try self.reportTextRelocError(symbol, rel, elf_file);539 try self.reportTextRelocError(symbol, rel, elf_file);
533 }540 }
534 }541 }
535 object.num_dynrelocs += 1;542 num_dynrelocs.* += 1;
536543
537 if (action == .ifunc) elf_file.num_ifunc_dynrelocs += 1;544 if (action == .ifunc) elf_file.num_ifunc_dynrelocs += 1;
538 },545 },
...@@ -898,9 +905,13 @@ fn resolveDynAbsReloc(...@@ -898,9 +905,13 @@ fn resolveDynAbsReloc(
898 const A = rel.r_addend;905 const A = rel.r_addend;
899 const S = @as(i64, @intCast(target.address(.{}, elf_file)));906 const S = @as(i64, @intCast(target.address(.{}, elf_file)));
900 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;907 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
901 const object = self.file(elf_file).?.object;
902908
903 try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, object.num_dynrelocs);909 const num_dynrelocs = switch (self.file(elf_file).?) {
910 .linker_defined => unreachable,
911 .shared_object => unreachable,
912 inline else => |x| x.num_dynrelocs,
913 };
914 try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, num_dynrelocs);
904915
905 switch (action) {916 switch (action) {
906 .@"error",917 .@"error",
...@@ -1165,7 +1176,7 @@ fn format2(...@@ -1165,7 +1176,7 @@ fn format2(
1165 _ = unused_fmt_string;1176 _ = unused_fmt_string;
1166 const atom = ctx.atom;1177 const atom = ctx.atom;
1167 const elf_file = ctx.elf_file;1178 const elf_file = ctx.elf_file;
1168 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x})", .{1179 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
1169 atom.atom_index, atom.name(elf_file), atom.value,1180 atom.atom_index, atom.name(elf_file), atom.value,
1170 atom.output_section_index, atom.alignment, atom.size,1181 atom.output_section_index, atom.alignment, atom.size,
1171 });1182 });
...@@ -1191,9 +1202,6 @@ pub const Flags = packed struct {...@@ -1191,9 +1202,6 @@ pub const Flags = packed struct {
11911202
1192 /// Specifies if the atom has been visited during garbage collection.1203 /// Specifies if the atom has been visited during garbage collection.
1193 visited: bool = false,1204 visited: bool = false,
1194
1195 /// Specifies whether this atom has been allocated in the output section.
1196 allocated: bool = false,
1197};1205};
11981206
1199const x86_64 = struct {1207const x86_64 = struct {
src/link/Elf/Symbol.zig+1-1
...@@ -314,7 +314,7 @@ fn format2(...@@ -314,7 +314,7 @@ fn format2(
314 try writer.writeAll(" : absolute");314 try writer.writeAll(" : absolute");
315 }315 }
316 } else if (symbol.outputShndx()) |shndx| {316 } else if (symbol.outputShndx()) |shndx| {
317 try writer.print(" : sect({d})", .{shndx});317 try writer.print(" : shdr({d})", .{shndx});
318 }318 }
319 if (symbol.atom(ctx.elf_file)) |atom_ptr| {319 if (symbol.atom(ctx.elf_file)) |atom_ptr| {
320 try writer.print(" : atom({d})", .{atom_ptr.atom_index});320 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
src/link/Elf/ZigModule.zig+26-1
...@@ -16,6 +16,8 @@ globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},...@@ -16,6 +16,8 @@ globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
16atoms: std.ArrayListUnmanaged(Atom.Index) = .{},16atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
17relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},17relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
1818
19num_dynrelocs: u32 = 0,
20
19output_symtab_size: Elf.SymtabSize = .{},21output_symtab_size: Elf.SymtabSize = .{},
2022
21pub fn deinit(self: *ZigModule, allocator: Allocator) void {23pub fn deinit(self: *ZigModule, allocator: Allocator) void {
...@@ -79,6 +81,22 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {...@@ -79,6 +81,22 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
79 return symbol_index;81 return symbol_index;
80}82}
8183
84/// TODO actually create fake input shdrs and return that instead.
85pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
86 _ = self;
87 const shdr = shdr: {
88 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
89 const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
90 var shdr = elf_file.shdrs.items[shndx];
91 shdr.sh_addr = 0;
92 shdr.sh_offset = 0;
93 shdr.sh_size = atom.size;
94 shdr.sh_addralign = atom.alignment.toByteUnits(1);
95 break :shdr shdr;
96 };
97 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
98}
99
82pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {100pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
83 for (self.globals(), 0..) |index, i| {101 for (self.globals(), 0..) |index, i| {
84 const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000;102 const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000;
...@@ -145,6 +163,8 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {...@@ -145,6 +163,8 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
145 for (self.atoms.items) |atom_index| {163 for (self.atoms.items) |atom_index| {
146 const atom = elf_file.atom(atom_index) orelse continue;164 const atom = elf_file.atom(atom_index) orelse continue;
147 if (!atom.flags.alive) continue;165 if (!atom.flags.alive) continue;
166 const shdr = atom.inputShdr(elf_file);
167 if (shdr.sh_type == elf.SHT_NOBITS) continue;
148 if (atom.scanRelocsRequiresCode(elf_file)) {168 if (atom.scanRelocsRequiresCode(elf_file)) {
149 // TODO ideally we don't have to fetch the code here.169 // TODO ideally we don't have to fetch the code here.
150 // Perhaps it would make sense to save the code until flushModule where we170 // Perhaps it would make sense to save the code until flushModule where we
...@@ -273,7 +293,10 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8...@@ -273,7 +293,10 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8
273 const code = try gpa.alloc(u8, size);293 const code = try gpa.alloc(u8, size);
274 errdefer gpa.free(code);294 errdefer gpa.free(code);
275 const amt = try elf_file.base.file.?.preadAll(code, file_offset);295 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
276 if (amt != code.len) return error.InputOutput;296 if (amt != code.len) {
297 log.err("fetching code for {s} failed", .{atom.name(elf_file)});
298 return error.InputOutput;
299 }
277 return code;300 return code;
278}301}
279302
...@@ -334,11 +357,13 @@ fn formatAtoms(...@@ -334,11 +357,13 @@ fn formatAtoms(
334const assert = std.debug.assert;357const assert = std.debug.assert;
335const std = @import("std");358const std = @import("std");
336const elf = std.elf;359const elf = std.elf;
360const log = std.log.scoped(.link);
337361
338const Allocator = std.mem.Allocator;362const Allocator = std.mem.Allocator;
339const Atom = @import("Atom.zig");363const Atom = @import("Atom.zig");
340const Elf = @import("../Elf.zig");364const Elf = @import("../Elf.zig");
341const File = @import("file.zig").File;365const File = @import("file.zig").File;
342const Module = @import("../../Module.zig");366const Module = @import("../../Module.zig");
367const Object = @import("Object.zig");
343const Symbol = @import("Symbol.zig");368const Symbol = @import("Symbol.zig");
344const ZigModule = @This();369const ZigModule = @This();