| author | |
| committer | |
| log | 85d451f96cd8f2854fa6a092625b8a2f3c474a73 |
| tree | 0c001659b2021fe860cb982f137aacf271a5e668 |
| parent | 7be983ac9217a596b7f35e7ef4c49fda0270e10b |
4 files changed, 110 insertions(+), 21 deletions(-)
src/link/Elf.zig+62-6| ... | ... | @@ -762,6 +762,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 762 | 762 | .name = ".zig.got", |
| 763 | 763 | .phdr_index = self.phdr_zig_got_index.?, |
| 764 | 764 | .alignment = ptr_size, |
| 765 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 765 | 766 | }); |
| 766 | 767 | } |
| 767 | 768 | |
| ... | ... | @@ -785,7 +786,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 785 | 786 | |
| 786 | 787 | if (self.zig_bss_section_index == null) { |
| 787 | 788 | self.zig_bss_section_index = try self.allocateAllocSection(.{ |
| 788 | .name = ".bss.zig", | |
| 789 | .name = ".zig.bss", | |
| 789 | 790 | .phdr_index = self.phdr_zig_load_zerofill_index.?, |
| 790 | 791 | .alignment = ptr_size, |
| 791 | 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 | 1559 | for (zig_module.atoms.items) |atom_index| { |
| 1559 | 1560 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1560 | 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 | 1564 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1563 | 1565 | const code = try zig_module.codeAlloc(self, atom_index); |
| 1564 | 1566 | defer gpa.free(code); |
| ... | ... | @@ -3744,6 +3746,9 @@ fn initSections(self: *Elf) !void { |
| 3744 | 3746 | const needs_rela_dyn = blk: { |
| 3745 | 3747 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or |
| 3746 | 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 | 3752 | for (self.objects.items) |index| { |
| 3748 | 3753 | if (self.file(index).?.object.num_dynrelocs > 0) break :blk true; |
| 3749 | 3754 | } |
| ... | ... | @@ -4243,6 +4248,33 @@ fn sortSections(self: *Elf) !void { |
| 4243 | 4248 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 4244 | 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 | } |
| 4247 | 4279 | |
| 4248 | 4280 | fn updateSectionSizes(self: *Elf) !void { |
| ... | ... | @@ -4286,6 +4318,9 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4286 | 4318 | |
| 4287 | 4319 | if (self.rela_dyn_section_index) |shndx| { |
| 4288 | 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 | 4324 | for (self.objects.items) |index| { |
| 4290 | 4325 | num += self.file(index).?.object.num_dynrelocs; |
| 4291 | 4326 | } |
| ... | ... | @@ -4373,9 +4408,10 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 { |
| 4373 | 4408 | fn calcNumberOfSegments(self: *Elf) usize { |
| 4374 | 4409 | var count: usize = 0; |
| 4375 | 4410 | var flags: u64 = 0; |
| 4376 | for (self.shdrs.items) |shdr| { | |
| 4411 | for (self.shdrs.items, 0..) |shdr, shndx| { | |
| 4377 | 4412 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4378 | 4413 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4414 | if (self.isZigSection(@intCast(shndx))) continue; | |
| 4379 | 4415 | if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1; |
| 4380 | 4416 | flags = shdrToPhdrFlags(shdr.sh_flags); |
| 4381 | 4417 | } |
| ... | ... | @@ -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 | } | |
| 4478 | 4517 | |
| 4479 | 4518 | // Now we can proceed with allocating the sections in virtual memory. |
| 4480 | 4519 | // As the base address we take the end address of the PHDR table. |
| ... | ... | @@ -4647,6 +4686,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4647 | 4686 | undefs.deinit(); |
| 4648 | 4687 | } |
| 4649 | 4688 | |
| 4689 | // TODO iterate over `output_sections` directly | |
| 4650 | 4690 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 4651 | 4691 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4652 | 4692 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| ... | ... | @@ -5830,7 +5870,10 @@ fn fmtDumpState( |
| 5830 | 5870 | if (self.zig_module_index) |index| { |
| 5831 | 5871 | const zig_module = self.file(index).?.zig_module; |
| 5832 | 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 | } |
| 5835 | 5878 | |
| 5836 | 5879 | for (self.objects.items) |index| { |
| ... | ... | @@ -5872,7 +5915,7 @@ fn fmtDumpState( |
| 5872 | 5915 | self.fmtShdr(shdr), |
| 5873 | 5916 | }); |
| 5874 | 5917 | } |
| 5875 | try writer.writeAll("Output phdrs\n"); | |
| 5918 | try writer.writeAll("\nOutput phdrs\n"); | |
| 5876 | 5919 | for (self.phdrs.items, 0..) |phdr, phndx| { |
| 5877 | 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 | 6026 | .st_size = 0, |
| 5984 | 6027 | }; |
| 5985 | 6028 | |
| 6029 | pub 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 | ||
| 5986 | 6042 | const SystemLib = struct { |
| 5987 | 6043 | needed: bool = false, |
| 5988 | 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 | 50 | } |
| 51 | 51 | |
| 52 | 52 | pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { |
| 53 | const object = self.file(elf_file).?.object; | |
| 54 | return object.shdrs.items[self.input_section_index]; | |
| 53 | return switch (self.file(elf_file).?) { | |
| 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 | } |
| 56 | 59 | |
| 57 | 60 | pub fn outputShndx(self: Atom) ?u16 { |
| ... | ... | @@ -199,7 +202,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 199 | 202 | _ = free_list.swapRemove(i); |
| 200 | 203 | } |
| 201 | 204 | |
| 202 | self.flags.allocated = true; | |
| 205 | self.flags.alive = true; | |
| 203 | 206 | } |
| 204 | 207 | |
| 205 | 208 | pub fn shrink(self: *Atom, elf_file: *Elf) void { |
| ... | ... | @@ -471,7 +474,11 @@ fn scanReloc( |
| 471 | 474 | elf_file: *Elf, |
| 472 | 475 | ) error{OutOfMemory}!void { |
| 473 | 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 | }; | |
| 475 | 482 | |
| 476 | 483 | switch (action) { |
| 477 | 484 | .none => {}, |
| ... | ... | @@ -500,7 +507,7 @@ fn scanReloc( |
| 500 | 507 | try self.reportTextRelocError(symbol, rel, elf_file); |
| 501 | 508 | } |
| 502 | 509 | } |
| 503 | object.num_dynrelocs += 1; | |
| 510 | num_dynrelocs.* += 1; | |
| 504 | 511 | } else { |
| 505 | 512 | symbol.flags.needs_copy_rel = true; |
| 506 | 513 | } |
| ... | ... | @@ -517,7 +524,7 @@ fn scanReloc( |
| 517 | 524 | |
| 518 | 525 | .dyn_cplt => { |
| 519 | 526 | if (is_writeable) { |
| 520 | object.num_dynrelocs += 1; | |
| 527 | num_dynrelocs.* += 1; | |
| 521 | 528 | } else { |
| 522 | 529 | symbol.flags.needs_plt = true; |
| 523 | 530 | symbol.flags.is_canonical = true; |
| ... | ... | @@ -532,7 +539,7 @@ fn scanReloc( |
| 532 | 539 | try self.reportTextRelocError(symbol, rel, elf_file); |
| 533 | 540 | } |
| 534 | 541 | } |
| 535 | object.num_dynrelocs += 1; | |
| 542 | num_dynrelocs.* += 1; | |
| 536 | 543 | |
| 537 | 544 | if (action == .ifunc) elf_file.num_ifunc_dynrelocs += 1; |
| 538 | 545 | }, |
| ... | ... | @@ -898,9 +905,13 @@ fn resolveDynAbsReloc( |
| 898 | 905 | const A = rel.r_addend; |
| 899 | 906 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); |
| 900 | 907 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; |
| 901 | const object = self.file(elf_file).?.object; | |
| 902 | 908 | |
| 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); | |
| 904 | 915 | |
| 905 | 916 | switch (action) { |
| 906 | 917 | .@"error", |
| ... | ... | @@ -1165,7 +1176,7 @@ fn format2( |
| 1165 | 1176 | _ = unused_fmt_string; |
| 1166 | 1177 | const atom = ctx.atom; |
| 1167 | 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 | 1180 | atom.atom_index, atom.name(elf_file), atom.value, |
| 1170 | 1181 | atom.output_section_index, atom.alignment, atom.size, |
| 1171 | 1182 | }); |
| ... | ... | @@ -1191,9 +1202,6 @@ pub const Flags = packed struct { |
| 1191 | 1202 | |
| 1192 | 1203 | /// Specifies if the atom has been visited during garbage collection. |
| 1193 | 1204 | visited: bool = false, |
| 1194 | ||
| 1195 | /// Specifies whether this atom has been allocated in the output section. | |
| 1196 | allocated: bool = false, | |
| 1197 | 1205 | }; |
| 1198 | 1206 | |
| 1199 | 1207 | const x86_64 = struct { |
src/link/Elf/Symbol.zig+1-1| ... | ... | @@ -314,7 +314,7 @@ fn format2( |
| 314 | 314 | try writer.writeAll(" : absolute"); |
| 315 | 315 | } |
| 316 | 316 | } else if (symbol.outputShndx()) |shndx| { |
| 317 | try writer.print(" : sect({d})", .{shndx}); | |
| 317 | try writer.print(" : shdr({d})", .{shndx}); | |
| 318 | 318 | } |
| 319 | 319 | if (symbol.atom(ctx.elf_file)) |atom_ptr| { |
| 320 | 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 | 16 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 17 | 17 | relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{}, |
| 18 | 18 | |
| 19 | num_dynrelocs: u32 = 0, | |
| 20 | ||
| 19 | 21 | output_symtab_size: Elf.SymtabSize = .{}, |
| 20 | 22 | |
| 21 | 23 | pub fn deinit(self: *ZigModule, allocator: Allocator) void { |
| ... | ... | @@ -79,6 +81,22 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index { |
| 79 | 81 | return symbol_index; |
| 80 | 82 | } |
| 81 | 83 | |
| 84 | /// TODO actually create fake input shdrs and return that instead. | |
| 85 | pub 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 | ||
| 82 | 100 | pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void { |
| 83 | 101 | for (self.globals(), 0..) |index, i| { |
| 84 | 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 | 163 | for (self.atoms.items) |atom_index| { |
| 146 | 164 | const atom = elf_file.atom(atom_index) orelse continue; |
| 147 | 165 | if (!atom.flags.alive) continue; |
| 166 | const shdr = atom.inputShdr(elf_file); | |
| 167 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | |
| 148 | 168 | if (atom.scanRelocsRequiresCode(elf_file)) { |
| 149 | 169 | // TODO ideally we don't have to fetch the code here. |
| 150 | 170 | // 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 | 293 | const code = try gpa.alloc(u8, size); |
| 274 | 294 | errdefer gpa.free(code); |
| 275 | 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 | 300 | return code; |
| 278 | 301 | } |
| 279 | 302 | |
| ... | ... | @@ -334,11 +357,13 @@ fn formatAtoms( |
| 334 | 357 | const assert = std.debug.assert; |
| 335 | 358 | const std = @import("std"); |
| 336 | 359 | const elf = std.elf; |
| 360 | const log = std.log.scoped(.link); | |
| 337 | 361 | |
| 338 | 362 | const Allocator = std.mem.Allocator; |
| 339 | 363 | const Atom = @import("Atom.zig"); |
| 340 | 364 | const Elf = @import("../Elf.zig"); |
| 341 | 365 | const File = @import("file.zig").File; |
| 342 | 366 | const Module = @import("../../Module.zig"); |
| 367 | const Object = @import("Object.zig"); | |
| 343 | 368 | const Symbol = @import("Symbol.zig"); |
| 344 | 369 | const ZigModule = @This(); |