diff --git a/CMakeLists.txt b/CMakeLists.txt index bdde42927eae3107c2a59ae600ccd84cc548a3a2..4b27fd555e344a5ddeaecf799315df296ceddb0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -594,7 +594,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig" - "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig" + "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigObject.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig" diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index ca796a4d71124a0fa341860a1531066814014296..51fb906e007dc2e4220d4dc37fabaf4c5f75e176 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -86,7 +86,7 @@ pub fn emitMir(emit: *Emit) Error!void { }), .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; - const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index)); + const sym = elf_file.symbol(elf_file.zigObjectPtr().?.symbol(data.sym_index)); if (emit.lower.bin_file.options.pic) { const r_type: u32 = if (sym.flags.has_zig_got) link.File.Elf.R_X86_64_ZIG_GOTPCREL diff --git a/src/codegen.zig b/src/codegen.zig index c46e41c6e6e1bc904367e62a9d0ca8cb622bd9af..4e31c1260338e56867459cfb24746ffcaed15fd2 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -904,7 +904,7 @@ fn genDeclRef( else null; const sym_index = try elf_file.getGlobalSymbol(name, lib_name); - elf_file.symbol(elf_file.zigModulePtr().symbol(sym_index)).flags.needs_got = true; + elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true; return GenResult.mcv(.{ .load_symbol = sym_index }); } const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 15a10f1b636d2c1fbec1e1b41ed1f80b4085f062..de1e9ce5b493fa1c0f182e7d409f4ec16500b8af 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -11,7 +11,7 @@ llvm_object: ?*LlvmObject = null, /// Index of each input file also encodes the priority or precedence of one input file /// over another. files: std.MultiArrayList(File.Entry) = .{}, -zig_module_index: ?File.Index = null, +zig_object_index: ?File.Index = null, linker_defined_index: ?File.Index = null, objects: std.ArrayListUnmanaged(File.Index) = .{}, shared_objects: std.ArrayListUnmanaged(File.Index) = .{}, @@ -327,24 +327,24 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option } const index = @as(File.Index, @intCast(try self.files.addOne(allocator))); - self.files.set(index, .{ .zig_module = .{ + self.files.set(index, .{ .zig_object = .{ .index = index, .path = options.module.?.main_mod.root_src_path, } }); - self.zig_module_index = index; - const zig_module = self.file(index).?.zig_module; + self.zig_object_index = index; + const zig_object = self.zigObjectPtr().?; - try zig_module.atoms.append(allocator, 0); // null input section + try zig_object.atoms.append(allocator, 0); // null input section const name_off = try self.strtab.insert(allocator, std.fs.path.stem(options.module.?.main_mod.root_src_path)); const symbol_index = try self.addSymbol(); - try zig_module.local_symbols.append(allocator, symbol_index); + try zig_object.local_symbols.append(allocator, symbol_index); const symbol_ptr = self.symbol(symbol_index); - symbol_ptr.file_index = zig_module.index; + symbol_ptr.file_index = zig_object.index; symbol_ptr.name_offset = name_off; - const esym_index = try zig_module.addLocalEsym(allocator); - const esym = &zig_module.local_esyms.items(.elf_sym)[esym_index]; + const esym_index = try zig_object.addLocalEsym(allocator); + const esym = &zig_object.local_esyms.items(.elf_sym)[esym_index]; esym.st_name = name_off; esym.st_info |= elf.STT_FILE; esym.st_shndx = elf.SHN_ABS; @@ -401,7 +401,7 @@ pub fn deinit(self: *Elf) void { for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) { .null => {}, - .zig_module => data.zig_module.deinit(gpa), + .zig_object => data.zig_object.deinit(gpa), .linker_defined => data.linker_defined.deinit(gpa), .object => data.object.deinit(gpa), .shared_object => data.shared_object.deinit(gpa), @@ -726,7 +726,7 @@ fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{ return index; } -/// TODO move to ZigModule +/// TODO move to ZigObject pub fn initMetadata(self: *Elf) !void { const gpa = self.base.allocator; const ptr_size = self.ptrWidthBytes(); @@ -1041,7 +1041,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } else null; const gc_sections = self.base.options.gc_sections orelse false; - if (self.base.options.output_mode == .Obj and self.zig_module_index == null) { + if (self.base.options.output_mode == .Obj and self.zig_object_index == null) { // TODO this will become -r route I guess. For now, just copy the object file. assert(self.base.file == null); // TODO uncomment once we implement -r const the_object_path = blk: { @@ -1543,7 +1543,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } // Now, we are ready to resolve the symbols across all input files. - // We will first resolve the files in the ZigModule, next in the parsed + // We will first resolve the files in the ZigObject, next in the parsed // input Object files. // Any qualifing unresolved symbol will be upgraded to an absolute, weak // symbol for potential resolution at load-time. @@ -1576,7 +1576,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Scan and create missing synthetic entries such as GOT indirection. try self.scanRelocs(); - // TODO I need to re-think how to handle ZigModule's debug sections AND debug sections + // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections // extracted from input object files correctly. if (self.dwarf) |*dw| { if (self.debug_abbrev_section_dirty) { @@ -1645,15 +1645,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Beyond this point, everything has been allocated a virtual address and we can resolve // the relocations, and commit objects to file. - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - for (zig_module.atoms.items) |atom_index| { + if (self.zigObjectPtr()) |zig_object| { + for (zig_object.atoms.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.flags.alive) continue; const out_shndx = atom_ptr.outputShndx() orelse continue; const shdr = &self.shdrs.items[out_shndx]; if (shdr.sh_type == elf.SHT_NOBITS) continue; - const code = try zig_module.codeAlloc(self, atom_index); + const code = try zig_object.codeAlloc(self, atom_index); defer gpa.free(code); const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { @@ -1926,8 +1925,8 @@ fn accessLibPath( /// 5. Remove references to dead objects/shared objects /// 6. Re-run symbol resolution on pruned objects and shared objects sets. fn resolveSymbols(self: *Elf) void { - // Resolve symbols in the ZigModule. For now, we assume that it's always live. - if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); + // Resolve symbols in the ZigObject. For now, we assume that it's always live. + if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self); // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); @@ -1936,7 +1935,7 @@ fn resolveSymbols(self: *Elf) void { self.markLive(); // Reset state of all globals after marking live objects. - if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self); + if (self.zigObjectPtr()) |zig_object| zig_object.resetGlobals(self); for (self.objects.items) |index| self.file(index).?.resetGlobals(self); for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self); @@ -1988,7 +1987,7 @@ fn resolveSymbols(self: *Elf) void { } // Re-resolve the symbols. - if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); + if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self); for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); } @@ -1998,7 +1997,7 @@ fn resolveSymbols(self: *Elf) void { /// This routine will prune unneeded objects extracted from archives and /// unneeded shared objects. fn markLive(self: *Elf) void { - if (self.zig_module_index) |index| self.file(index).?.markLive(self); + if (self.zigObjectPtr()) |zig_object| zig_object.markLive(self); for (self.objects.items) |index| { const file_ptr = self.file(index).?; if (file_ptr.isAlive()) file_ptr.markLive(self); @@ -2057,7 +2056,7 @@ fn markImportsExports(self: *Elf) void { } } - if (self.zig_module_index) |index| { + if (self.zig_object_index) |index| { mark(self, index); } @@ -2067,9 +2066,8 @@ fn markImportsExports(self: *Elf) void { } fn claimUnresolved(self: *Elf) void { - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - zig_module.claimUnresolved(self); + if (self.zigObjectPtr()) |zig_object| { + zig_object.claimUnresolved(self); } for (self.objects.items) |index| { const object = self.file(index).?.object; @@ -2093,9 +2091,8 @@ fn scanRelocs(self: *Elf) !void { undefs.deinit(); } - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - try zig_module.scanRelocs(self, &undefs); + if (self.zigObjectPtr()) |zig_object| { + try zig_object.scanRelocs(self, &undefs); } for (self.objects.items) |index| { const object = self.file(index).?.object; @@ -3114,9 +3111,9 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymb .state = &gop.value_ptr.rodata_state, }, }; - const zig_module = self.file(self.zig_module_index.?).?.zig_module; + const zig_object = self.zigObjectPtr().?; switch (metadata.state.*) { - .unused => metadata.symbol_index.* = try zig_module.addAtom(self), + .unused => metadata.symbol_index.* = try zig_object.addAtom(self), .pending_flush => return metadata.symbol_index.*, .flushed => {}, } @@ -3130,8 +3127,8 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymb pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Symbol.Index { const gop = try self.decls.getOrPut(self.base.allocator, decl_index); if (!gop.found_existing) { - const zig_module = self.file(self.zig_module_index.?).?.zig_module; - gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) }; + const zig_object = self.zigObjectPtr().?; + gop.value_ptr.* = .{ .symbol_index = try zig_object.addAtom(self) }; } return gop.value_ptr.symbol_index; } @@ -3173,7 +3170,7 @@ fn updateDeclCode( ) !void { const gpa = self.base.allocator; const mod = self.base.options.module.?; - const zig_module = self.file(self.zig_module_index.?).?.zig_module; + const zig_object = self.zigObjectPtr().?; const decl = mod.declPtr(decl_index); const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); @@ -3182,7 +3179,7 @@ fn updateDeclCode( const required_alignment = decl.getAlignment(mod); const sym = self.symbol(sym_index); - const esym = &zig_module.local_esyms.items(.elf_sym)[sym.esym_index]; + const esym = &zig_object.local_esyms.items(.elf_sym)[sym.esym_index]; const atom_ptr = sym.atom(self).?; const shdr_index = self.getDeclShdrIndex(decl_index, code); @@ -3340,7 +3337,7 @@ pub fn updateDecl( const name = mod.intern_pool.stringToSlice(decl.name); const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); const esym_index = try self.getGlobalSymbol(name, lib_name); - self.symbol(self.zigModulePtr().symbol(esym_index)).flags.needs_got = true; + self.symbol(self.zigObjectPtr().?.symbol(esym_index)).flags.needs_got = true; return; } @@ -3401,7 +3398,7 @@ pub fn updateDecl( fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.Index) !void { const gpa = self.base.allocator; const mod = self.base.options.module.?; - const zig_module = self.file(self.zig_module_index.?).?.zig_module; + const zig_object = self.zigObjectPtr().?; var required_alignment: InternPool.Alignment = .none; var code_buffer = std.ArrayList(u8).init(gpa); @@ -3449,7 +3446,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?; local_sym.name_offset = name_str_index; local_sym.output_section_index = output_section_index; - const local_esym = &zig_module.local_esyms.items(.elf_sym)[local_sym.esym_index]; + const local_esym = &zig_object.local_esyms.items(.elf_sym)[local_sym.esym_index]; local_esym.st_name = name_str_index; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; @@ -3519,8 +3516,8 @@ fn lowerConst( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - const zig_module = self.file(self.zig_module_index.?).?.zig_module; - const sym_index = try zig_module.addAtom(self); + const zig_object = self.zigObjectPtr().?; + const sym_index = try zig_object.addAtom(self); const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{ .none = {}, @@ -3537,7 +3534,7 @@ fn lowerConst( const name_str_index = try self.strtab.insert(gpa, name); local_sym.name_offset = name_str_index; local_sym.output_section_index = output_section_index; - const local_esym = &zig_module.local_esyms.items(.elf_sym)[local_sym.esym_index]; + const local_esym = &zig_object.local_esyms.items(.elf_sym)[local_sym.esym_index]; local_esym.st_name = name_str_index; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; @@ -3579,7 +3576,7 @@ pub fn updateExports( defer tracy.end(); const gpa = self.base.allocator; - const zig_module = self.file(self.zig_module_index.?).?.zig_module; + const zig_object = self.zigObjectPtr().?; const metadata = switch (exported) { .decl_index => |decl_index| blk: { _ = try self.getOrCreateMetadataForDecl(decl_index); @@ -3603,8 +3600,8 @@ pub fn updateExports( }; const sym_index = metadata.symbol_index; const esym_index = self.symbol(sym_index).esym_index; - const esym = zig_module.local_esyms.items(.elf_sym)[esym_index]; - const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index]; + const esym = zig_object.local_esyms.items(.elf_sym)[esym_index]; + const esym_shndx = zig_object.local_esyms.items(.shndx)[esym_index]; for (exports) |exp| { if (exp.opts.section.unwrap()) |section_name| { @@ -3638,24 +3635,24 @@ pub fn updateExports( const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); const name_off = try self.strtab.insert(gpa, exp_name); const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: { - const global_esym_index = try zig_module.addGlobalEsym(gpa); - const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off); - const global_esym = zig_module.elfSym(global_esym_index); + const global_esym_index = try zig_object.addGlobalEsym(gpa); + const lookup_gop = try zig_object.globals_lookup.getOrPut(gpa, name_off); + const global_esym = zig_object.elfSym(global_esym_index); global_esym.st_name = name_off; lookup_gop.value_ptr.* = global_esym_index; try metadata.exports.append(gpa, global_esym_index); const gop = try self.getOrPutGlobal(name_off); - try zig_module.global_symbols.append(gpa, gop.index); + try zig_object.global_symbols.append(gpa, gop.index); break :blk global_esym_index; }; - const actual_esym_index = global_esym_index & ZigModule.symbol_mask; - const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index]; + const actual_esym_index = global_esym_index & ZigObject.symbol_mask; + const global_esym = &zig_object.global_esyms.items(.elf_sym)[actual_esym_index]; global_esym.st_value = self.symbol(sym_index).value; global_esym.st_shndx = esym.st_shndx; global_esym.st_info = (stb_bits << 4) | stt_bits; global_esym.st_name = name_off; - zig_module.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx; + zig_object.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx; } } @@ -3683,20 +3680,20 @@ pub fn deleteDeclExport( if (self.llvm_object) |_| return; const metadata = self.decls.getPtr(decl_index) orelse return; const mod = self.base.options.module.?; - const zig_module = self.file(self.zig_module_index.?).?.zig_module; + const zig_object = self.zigObjectPtr().?; const exp_name = mod.intern_pool.stringToSlice(name); const esym_index = metadata.@"export"(self, exp_name) orelse return; log.debug("deleting export '{s}'", .{exp_name}); - const esym = &zig_module.global_esyms.items(.elf_sym)[esym_index.*]; - _ = zig_module.globals_lookup.remove(esym.st_name); + const esym = &zig_object.global_esyms.items(.elf_sym)[esym_index.*]; + _ = zig_object.globals_lookup.remove(esym.st_name); const sym_index = self.resolver.get(esym.st_name).?; const sym = self.symbol(sym_index); - if (sym.file_index == zig_module.index) { + if (sym.file_index == zig_object.index) { _ = self.resolver.swapRemove(esym.st_name); sym.* = .{}; } esym.* = null_sym; - zig_module.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; + zig_object.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; } fn addLinkerDefinedSymbols(self: *Elf) !void { @@ -3917,8 +3914,8 @@ fn initSections(self: *Elf) !void { const needs_rela_dyn = blk: { if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true; - if (self.zig_module_index) |index| { - if (self.file(index).?.zig_module.num_dynrelocs > 0) break :blk true; + if (self.zigObjectPtr()) |zig_object| { + if (zig_object.num_dynrelocs > 0) break :blk true; } for (self.objects.items) |index| { if (self.file(index).?.object.num_dynrelocs > 0) break :blk true; @@ -4512,16 +4509,15 @@ fn sortShdrs(self: *Elf) !void { } } - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - for (zig_module.atoms.items) |atom_index| { + if (self.zigObjectPtr()) |zig_object| { + for (zig_object.atoms.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.flags.alive) continue; const out_shndx = atom_ptr.outputShndx() orelse continue; atom_ptr.output_section_index = backlinks[out_shndx]; } - for (zig_module.locals()) |local_index| { + for (zig_object.locals()) |local_index| { const local = self.symbol(local_index); const atom_ptr = local.atom(self) orelse continue; if (!atom_ptr.flags.alive) continue; @@ -4529,11 +4525,11 @@ fn sortShdrs(self: *Elf) !void { local.output_section_index = backlinks[out_shndx]; } - for (zig_module.globals()) |global_index| { + for (zig_object.globals()) |global_index| { const global = self.symbol(global_index); const atom_ptr = global.atom(self) orelse continue; if (!atom_ptr.flags.alive) continue; - if (global.file(self).?.index() != index) continue; + if (global.file(self).?.index() != zig_object.index) continue; const out_shndx = global.outputShndx() orelse continue; global.output_section_index = backlinks[out_shndx]; } @@ -4599,8 +4595,8 @@ fn updateSectionSizes(self: *Elf) !void { if (self.rela_dyn_section_index) |shndx| { var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela(); - if (self.zig_module_index) |index| { - num += self.file(index).?.zig_module.num_dynrelocs; + if (self.zigObjectPtr()) |zig_object| { + num += zig_object.num_dynrelocs; } for (self.objects.items) |index| { num += self.file(index).?.object.num_dynrelocs; @@ -5079,11 +5075,10 @@ fn writeAtoms(self: *Elf) !void { fn updateSymtabSize(self: *Elf) !void { var sizes = SymtabSize{}; - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - zig_module.updateSymtabSize(self); - sizes.nlocals += zig_module.output_symtab_size.nlocals; - sizes.nglobals += zig_module.output_symtab_size.nglobals; + if (self.zigObjectPtr()) |zig_object| { + zig_object.updateSymtabSize(self); + sizes.nlocals += zig_object.output_symtab_size.nlocals; + sizes.nglobals += zig_object.output_symtab_size.nglobals; } for (self.objects.items) |index| { @@ -5299,11 +5294,10 @@ fn writeSymtab(self: *Elf) !void { .symtab = symtab, }; - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - zig_module.writeSymtab(self, ctx); - ctx.ilocal += zig_module.output_symtab_size.nlocals; - ctx.iglobal += zig_module.output_symtab_size.nglobals; + if (self.zigObjectPtr()) |zig_object| { + zig_object.writeSymtab(self, ctx); + ctx.ilocal += zig_object.output_symtab_size.nlocals; + ctx.iglobal += zig_object.output_symtab_size.nglobals; } for (self.objects.items) |index| { @@ -5863,7 +5857,7 @@ pub fn file(self: *Elf, index: File.Index) ?File { return switch (tag) { .null => null, .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined }, - .zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module }, + .zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object }, .object => .{ .object = &self.files.items(.data)[index].object }, .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object }, }; @@ -5964,23 +5958,22 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 _ = lib_name; const gpa = self.base.allocator; const off = try self.strtab.insert(gpa, name); - const zig_module = self.file(self.zig_module_index.?).?.zig_module; - const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, off); + const zig_object = self.zigObjectPtr().?; + const lookup_gop = try zig_object.globals_lookup.getOrPut(gpa, off); if (!lookup_gop.found_existing) { - const esym_index = try zig_module.addGlobalEsym(gpa); - const esym = zig_module.elfSym(esym_index); + const esym_index = try zig_object.addGlobalEsym(gpa); + const esym = zig_object.elfSym(esym_index); esym.st_name = off; lookup_gop.value_ptr.* = esym_index; const gop = try self.getOrPutGlobal(off); - try zig_module.global_symbols.append(gpa, gop.index); + try zig_object.global_symbols.append(gpa, gop.index); } return lookup_gop.value_ptr.*; } -pub fn zigModulePtr(self: *Elf) *ZigModule { - assert(self.zig_module_index != null); - const file_ptr = self.file(self.zig_module_index.?).?; - return file_ptr.zig_module; +pub fn zigObjectPtr(self: *Elf) ?*ZigObject { + const index = self.zig_object_index orelse return null; + return self.file(index).?.zig_object; } const GetOrCreateComdatGroupOwnerResult = struct { @@ -6245,12 +6238,11 @@ fn fmtDumpState( _ = unused_fmt_string; _ = options; - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path }); + if (self.zigObjectPtr()) |zig_object| { + try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path }); try writer.print("{}{}\n", .{ - zig_module.fmtAtoms(self), - zig_module.fmtSymtab(self), + zig_object.fmtAtoms(self), + zig_object.fmtSymtab(self), }); } @@ -6379,9 +6371,9 @@ const DeclMetadata = struct { exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { - const zig_module = elf_file.file(elf_file.zig_module_index.?).?.zig_module; + const zig_object = elf_file.zigObjectPtr().?; for (m.exports.items) |*exp| { - const exp_name = elf_file.strtab.getAssumeExists(zig_module.elfSym(exp.*).st_name); + const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name); if (mem.eql(u8, name, exp_name)) return exp; } return null; @@ -6491,4 +6483,4 @@ const TypedValue = @import("../TypedValue.zig"); const Value = @import("../value.zig").Value; const VerneedSection = synthetic_sections.VerneedSection; const ZigGotSection = synthetic_sections.ZigGotSection; -const ZigModule = @import("Elf/ZigModule.zig"); +const ZigObject = @import("Elf/ZigObject.zig"); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index abfaf3b337dcbe0f7bd212a1d1fcbc58a16414c7..02e29599e9afbe35d14f353aefa64607e4f38bdd 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -52,7 +52,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { return switch (self.file(elf_file).?) { .object => |x| x.shdrs.items[self.input_section_index], - .zig_module => |x| x.inputShdr(self.atom_index, elf_file), + .zig_object => |x| x.inputShdr(self.atom_index, elf_file), else => unreachable, }; } @@ -270,14 +270,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void { // TODO create relocs free list self.freeRelocs(elf_file); // TODO figure out how to free input section mappind in ZigModule - // const zig_module = self.file(elf_file).?.zig_module; - // assert(zig_module.atoms.swapRemove(self.atom_index)); + // const zig_object = elf_file.zigObjectPtr().? + // assert(zig_object.atoms.swapRemove(self.atom_index)); self.* = .{}; } pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { return switch (self.file(elf_file).?) { - .zig_module => |x| x.relocs.items[self.relocs_section_index].items, + .zig_object => |x| x.relocs.items[self.relocs_section_index].items, .object => |x| x.getRelocs(self.relocs_section_index), else => unreachable, }; @@ -298,17 +298,17 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void { pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void { const gpa = elf_file.base.allocator; const file_ptr = self.file(elf_file).?; - assert(file_ptr == .zig_module); - const zig_module = file_ptr.zig_module; - const rels = &zig_module.relocs.items[self.relocs_section_index]; + assert(file_ptr == .zig_object); + const zig_object = file_ptr.zig_object; + const rels = &zig_object.relocs.items[self.relocs_section_index]; try rels.append(gpa, reloc); } pub fn freeRelocs(self: Atom, elf_file: *Elf) void { const file_ptr = self.file(elf_file).?; - assert(file_ptr == .zig_module); - const zig_module = file_ptr.zig_module; - zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity(); + assert(file_ptr == .zig_object); + const zig_object = file_ptr.zig_object; + zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity(); } pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { @@ -332,7 +332,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const symbol_index = switch (file_ptr) { - .zig_module => |x| x.symbol(rel.r_sym()), + .zig_object => |x| x.symbol(rel.r_sym()), .object => |x| x.symbols.items[rel.r_sym()], else => unreachable, }; @@ -690,7 +690,7 @@ fn reportUndefined( undefs: anytype, ) !void { const rel_esym = switch (self.file(elf_file).?) { - .zig_module => |x| x.elfSym(rel.r_sym()).*, + .zig_object => |x| x.elfSym(rel.r_sym()).*, .object => |x| x.symtab[rel.r_sym()], else => unreachable, }; @@ -724,7 +724,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { if (r_type == elf.R_X86_64_NONE) continue; const target = switch (file_ptr) { - .zig_module => |x| elf_file.symbol(x.symbol(rel.r_sym())), + .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())), .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), else => unreachable, }; @@ -1004,7 +1004,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const target_index = switch (file_ptr) { - .zig_module => |x| x.symbol(rel.r_sym()), + .zig_object => |x| x.symbol(rel.r_sym()), .object => |x| x.symbols.items[rel.r_sym()], else => unreachable, }; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 00e6e15a8af83515679b326a84e8b5eaee2f6fcd..f6a6e91898d5678f341916f33ea39008318ba6c3 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -72,7 +72,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File { pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { const file_ptr = symbol.file(elf_file).?; switch (file_ptr) { - .zig_module => |x| return x.elfSym(symbol.esym_index).*, + .zig_object => |x| return x.elfSym(symbol.esym_index).*, .linker_defined => |x| return x.symtab.items[symbol.esym_index], inline else => |x| return x.symtab[symbol.esym_index], } @@ -406,4 +406,3 @@ const PltSection = synthetic_sections.PltSection; const SharedObject = @import("SharedObject.zig"); const Symbol = @This(); const ZigGotSection = synthetic_sections.ZigGotSection; -const ZigModule = @import("ZigModule.zig"); diff --git a/src/link/Elf/ZigModule.zig b/src/link/Elf/ZigModule.zig deleted file mode 100644 index 15f82113d9647579f7f6cae06ae56a1bff7c2e60..0000000000000000000000000000000000000000 --- a/src/link/Elf/ZigModule.zig +++ /dev/null @@ -1,381 +0,0 @@ -//! ZigModule encapsulates the state of the incrementally compiled Zig module. -//! It stores the associated input local and global symbols, allocated atoms, -//! and any relocations that may have been emitted. -//! Think about this as fake in-memory Object file for the Zig module. - -/// Path is owned by Module and lives as long as *Module. -path: []const u8, -index: File.Index, - -local_esyms: std.MultiArrayList(ElfSym) = .{}, -global_esyms: std.MultiArrayList(ElfSym) = .{}, -local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, -global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, -globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, - -atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, -relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{}, - -num_dynrelocs: u32 = 0, - -output_symtab_size: Elf.SymtabSize = .{}, - -pub const global_symbol_bit: u32 = 0x80000000; -pub const symbol_mask: u32 = 0x7fffffff; -pub const SHN_ATOM: u16 = 0x100; - -pub fn deinit(self: *ZigModule, allocator: Allocator) void { - self.local_esyms.deinit(allocator); - self.global_esyms.deinit(allocator); - self.local_symbols.deinit(allocator); - self.global_symbols.deinit(allocator); - self.globals_lookup.deinit(allocator); - self.atoms.deinit(allocator); - for (self.relocs.items) |*list| { - list.deinit(allocator); - } - self.relocs.deinit(allocator); -} - -pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index { - try self.local_esyms.ensureUnusedCapacity(allocator, 1); - const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity())); - var esym = ElfSym{ .elf_sym = Elf.null_sym }; - esym.elf_sym.st_info = elf.STB_LOCAL << 4; - self.local_esyms.set(index, esym); - return index; -} - -pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index { - try self.global_esyms.ensureUnusedCapacity(allocator, 1); - const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity())); - var esym = ElfSym{ .elf_sym = Elf.null_sym }; - esym.elf_sym.st_info = elf.STB_GLOBAL << 4; - self.global_esyms.set(index, esym); - return index | global_symbol_bit; -} - -pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index { - const gpa = elf_file.base.allocator; - - const atom_index = try elf_file.addAtom(); - const symbol_index = try elf_file.addSymbol(); - const esym_index = try self.addLocalEsym(gpa); - - const shndx = @as(u32, @intCast(self.atoms.items.len)); - try self.atoms.append(gpa, atom_index); - try self.local_symbols.append(gpa, symbol_index); - - const atom_ptr = elf_file.atom(atom_index).?; - atom_ptr.file_index = self.index; - - const symbol_ptr = elf_file.symbol(symbol_index); - symbol_ptr.file_index = self.index; - symbol_ptr.atom_index = atom_index; - - self.local_esyms.items(.shndx)[esym_index] = shndx; - self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; - symbol_ptr.esym_index = esym_index; - - const relocs_index = @as(u32, @intCast(self.relocs.items.len)); - const relocs = try self.relocs.addOne(gpa); - relocs.* = .{}; - atom_ptr.relocs_section_index = relocs_index; - - return symbol_index; -} - -/// TODO actually create fake input shdrs and return that instead. -pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { - _ = self; - const shdr = shdr: { - const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr; - const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr; - var shdr = elf_file.shdrs.items[shndx]; - shdr.sh_addr = 0; - shdr.sh_offset = 0; - shdr.sh_size = atom.size; - shdr.sh_addralign = atom.alignment.toByteUnits(1); - break :shdr shdr; - }; - return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable; -} - -pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; - const esym = self.global_esyms.items(.elf_sym)[i]; - const shndx = self.global_esyms.items(.shndx)[i]; - - if (esym.st_shndx == elf.SHN_UNDEF) continue; - - if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { - assert(esym.st_shndx == SHN_ATOM); - const atom_index = self.atoms.items[shndx]; - const atom = elf_file.atom(atom_index) orelse continue; - if (!atom.flags.alive) continue; - } - - const global = elf_file.symbol(index); - if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) { - const atom_index = switch (esym.st_shndx) { - elf.SHN_ABS, elf.SHN_COMMON => 0, - SHN_ATOM => self.atoms.items[shndx], - else => unreachable, - }; - const output_section_index = if (elf_file.atom(atom_index)) |atom| - atom.outputShndx().? - else - elf.SHN_UNDEF; - global.value = esym.st_value; - global.atom_index = atom_index; - global.esym_index = esym_index; - global.file_index = self.index; - global.output_section_index = output_section_index; - global.version_index = elf_file.default_sym_version; - if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; - } - } -} - -pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; - const esym = self.global_esyms.items(.elf_sym)[i]; - - if (esym.st_shndx != elf.SHN_UNDEF) continue; - - const global = elf_file.symbol(index); - if (global.file(elf_file)) |_| { - if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue; - } - - const is_import = blk: { - if (!elf_file.isDynLib()) break :blk false; - const vis = @as(elf.STV, @enumFromInt(esym.st_other)); - if (vis == .HIDDEN) break :blk false; - break :blk true; - }; - - global.value = 0; - global.atom_index = 0; - global.esym_index = esym_index; - global.file_index = self.index; - global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; - global.flags.import = is_import; - } -} - -pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void { - for (self.atoms.items) |atom_index| { - const atom = elf_file.atom(atom_index) orelse continue; - if (!atom.flags.alive) continue; - const shdr = atom.inputShdr(elf_file); - if (shdr.sh_type == elf.SHT_NOBITS) continue; - if (atom.scanRelocsRequiresCode(elf_file)) { - // TODO ideally we don't have to fetch the code here. - // Perhaps it would make sense to save the code until flushModule where we - // would free all of generated code? - const code = try self.codeAlloc(elf_file, atom_index); - defer elf_file.base.allocator.free(code); - try atom.scanRelocs(elf_file, code, undefs); - } else try atom.scanRelocs(elf_file, null, undefs); - } -} - -pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void { - for (self.globals()) |index| { - const global = elf_file.symbol(index); - const off = global.name_offset; - global.* = .{}; - global.name_offset = off; - } -} - -pub fn markLive(self: *ZigModule, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym = self.global_esyms.items(.elf_sym)[i]; - if (esym.st_bind() == elf.STB_WEAK) continue; - - const global = elf_file.symbol(index); - const file = global.file(elf_file) orelse continue; - const should_keep = esym.st_shndx == elf.SHN_UNDEF or - (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON); - if (should_keep and !file.isAlive()) { - file.setAlive(); - file.markLive(elf_file); - } - } -} - -pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); - const esym = local.elfSym(elf_file); - switch (esym.st_type()) { - elf.STT_SECTION, elf.STT_NOTYPE => { - local.flags.output_symtab = false; - continue; - }, - else => {}, - } - local.flags.output_symtab = true; - self.output_symtab_size.nlocals += 1; - } - - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - if (global.file(elf_file)) |file| if (file.index() != self.index) { - global.flags.output_symtab = false; - continue; - }; - global.flags.output_symtab = true; - if (global.isLocal()) { - self.output_symtab_size.nlocals += 1; - } else { - self.output_symtab_size.nglobals += 1; - } - } -} - -pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void { - var ilocal = ctx.ilocal; - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); - if (!local.flags.output_symtab) continue; - local.setOutputSym(elf_file, &ctx.symtab[ilocal]); - ilocal += 1; - } - - var iglobal = ctx.iglobal; - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - if (global.file(elf_file)) |file| if (file.index() != self.index) continue; - if (!global.flags.output_symtab) continue; - if (global.isLocal()) { - global.setOutputSym(elf_file, &ctx.symtab[ilocal]); - ilocal += 1; - } else { - global.setOutputSym(elf_file, &ctx.symtab[iglobal]); - iglobal += 1; - } - } -} - -pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index { - const is_global = index & global_symbol_bit != 0; - const actual_index = index & symbol_mask; - if (is_global) return self.global_symbols.items[actual_index]; - return self.local_symbols.items[actual_index]; -} - -pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym { - const is_global = index & global_symbol_bit != 0; - const actual_index = index & symbol_mask; - if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index]; - return &self.local_esyms.items(.elf_sym)[actual_index]; -} - -pub fn locals(self: *ZigModule) []const Symbol.Index { - return self.local_symbols.items; -} - -pub fn globals(self: *ZigModule) []const Symbol.Index { - return self.global_symbols.items; -} - -pub fn asFile(self: *ZigModule) File { - return .{ .zig_module = self }; -} - -/// Returns atom's code. -/// Caller owns the memory. -pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { - const gpa = elf_file.base.allocator; - const atom = elf_file.atom(atom_index).?; - assert(atom.file_index == self.index); - const shdr = &elf_file.shdrs.items[atom.outputShndx().?]; - const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr; - const size = std.math.cast(usize, atom.size) orelse return error.Overflow; - const code = try gpa.alloc(u8, size); - errdefer gpa.free(code); - const amt = try elf_file.base.file.?.preadAll(code, file_offset); - if (amt != code.len) { - log.err("fetching code for {s} failed", .{atom.name(elf_file)}); - return error.InputOutput; - } - return code; -} - -pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { - return .{ .data = .{ - .self = self, - .elf_file = elf_file, - } }; -} - -const FormatContext = struct { - self: *ZigModule, - elf_file: *Elf, -}; - -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = unused_fmt_string; - _ = options; - try writer.writeAll(" locals\n"); - for (ctx.self.locals()) |index| { - const local = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); - } - try writer.writeAll(" globals\n"); - for (ctx.self.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); - } -} - -pub fn fmtAtoms(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatAtoms) { - return .{ .data = .{ - .self = self, - .elf_file = elf_file, - } }; -} - -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = unused_fmt_string; - _ = options; - try writer.writeAll(" atoms\n"); - for (ctx.self.atoms.items) |atom_index| { - const atom = ctx.elf_file.atom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)}); - } -} - -const ElfSym = struct { - elf_sym: elf.Elf64_Sym, - shndx: u32 = elf.SHN_UNDEF, -}; - -const assert = std.debug.assert; -const std = @import("std"); -const elf = std.elf; -const log = std.log.scoped(.link); - -const Allocator = std.mem.Allocator; -const Atom = @import("Atom.zig"); -const Elf = @import("../Elf.zig"); -const File = @import("file.zig").File; -const Module = @import("../../Module.zig"); -const Object = @import("Object.zig"); -const Symbol = @import("Symbol.zig"); -const ZigModule = @This(); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig new file mode 100644 index 0000000000000000000000000000000000000000..26bab95fdf529d774c13c9038f7f082a88842ab2 --- /dev/null +++ b/src/link/Elf/ZigObject.zig @@ -0,0 +1,381 @@ +//! ZigModule encapsulates the state of the incrementally compiled Zig module. +//! It stores the associated input local and global symbols, allocated atoms, +//! and any relocations that may have been emitted. +//! Think about this as fake in-memory Object file for the Zig module. + +/// Path is owned by Module and lives as long as *Module. +path: []const u8, +index: File.Index, + +local_esyms: std.MultiArrayList(ElfSym) = .{}, +global_esyms: std.MultiArrayList(ElfSym) = .{}, +local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, +global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, +globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, + +atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, +relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{}, + +num_dynrelocs: u32 = 0, + +output_symtab_size: Elf.SymtabSize = .{}, + +pub const global_symbol_bit: u32 = 0x80000000; +pub const symbol_mask: u32 = 0x7fffffff; +pub const SHN_ATOM: u16 = 0x100; + +pub fn deinit(self: *ZigModule, allocator: Allocator) void { + self.local_esyms.deinit(allocator); + self.global_esyms.deinit(allocator); + self.local_symbols.deinit(allocator); + self.global_symbols.deinit(allocator); + self.globals_lookup.deinit(allocator); + self.atoms.deinit(allocator); + for (self.relocs.items) |*list| { + list.deinit(allocator); + } + self.relocs.deinit(allocator); +} + +pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index { + try self.local_esyms.ensureUnusedCapacity(allocator, 1); + const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity())); + var esym = ElfSym{ .elf_sym = Elf.null_sym }; + esym.elf_sym.st_info = elf.STB_LOCAL << 4; + self.local_esyms.set(index, esym); + return index; +} + +pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index { + try self.global_esyms.ensureUnusedCapacity(allocator, 1); + const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity())); + var esym = ElfSym{ .elf_sym = Elf.null_sym }; + esym.elf_sym.st_info = elf.STB_GLOBAL << 4; + self.global_esyms.set(index, esym); + return index | global_symbol_bit; +} + +pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index { + const gpa = elf_file.base.allocator; + + const atom_index = try elf_file.addAtom(); + const symbol_index = try elf_file.addSymbol(); + const esym_index = try self.addLocalEsym(gpa); + + const shndx = @as(u32, @intCast(self.atoms.items.len)); + try self.atoms.append(gpa, atom_index); + try self.local_symbols.append(gpa, symbol_index); + + const atom_ptr = elf_file.atom(atom_index).?; + atom_ptr.file_index = self.index; + + const symbol_ptr = elf_file.symbol(symbol_index); + symbol_ptr.file_index = self.index; + symbol_ptr.atom_index = atom_index; + + self.local_esyms.items(.shndx)[esym_index] = shndx; + self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; + symbol_ptr.esym_index = esym_index; + + const relocs_index = @as(u32, @intCast(self.relocs.items.len)); + const relocs = try self.relocs.addOne(gpa); + relocs.* = .{}; + atom_ptr.relocs_section_index = relocs_index; + + return symbol_index; +} + +/// TODO actually create fake input shdrs and return that instead. +pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { + _ = self; + const shdr = shdr: { + const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr; + const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr; + var shdr = elf_file.shdrs.items[shndx]; + shdr.sh_addr = 0; + shdr.sh_offset = 0; + shdr.sh_size = atom.size; + shdr.sh_addralign = atom.alignment.toByteUnits(1); + break :shdr shdr; + }; + return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable; +} + +pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void { + for (self.globals(), 0..) |index, i| { + const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; + const esym = self.global_esyms.items(.elf_sym)[i]; + const shndx = self.global_esyms.items(.shndx)[i]; + + if (esym.st_shndx == elf.SHN_UNDEF) continue; + + if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { + assert(esym.st_shndx == SHN_ATOM); + const atom_index = self.atoms.items[shndx]; + const atom = elf_file.atom(atom_index) orelse continue; + if (!atom.flags.alive) continue; + } + + const global = elf_file.symbol(index); + if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) { + const atom_index = switch (esym.st_shndx) { + elf.SHN_ABS, elf.SHN_COMMON => 0, + SHN_ATOM => self.atoms.items[shndx], + else => unreachable, + }; + const output_section_index = if (elf_file.atom(atom_index)) |atom| + atom.outputShndx().? + else + elf.SHN_UNDEF; + global.value = esym.st_value; + global.atom_index = atom_index; + global.esym_index = esym_index; + global.file_index = self.index; + global.output_section_index = output_section_index; + global.version_index = elf_file.default_sym_version; + if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; + } + } +} + +pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void { + for (self.globals(), 0..) |index, i| { + const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; + const esym = self.global_esyms.items(.elf_sym)[i]; + + if (esym.st_shndx != elf.SHN_UNDEF) continue; + + const global = elf_file.symbol(index); + if (global.file(elf_file)) |_| { + if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue; + } + + const is_import = blk: { + if (!elf_file.isDynLib()) break :blk false; + const vis = @as(elf.STV, @enumFromInt(esym.st_other)); + if (vis == .HIDDEN) break :blk false; + break :blk true; + }; + + global.value = 0; + global.atom_index = 0; + global.esym_index = esym_index; + global.file_index = self.index; + global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; + global.flags.import = is_import; + } +} + +pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void { + for (self.atoms.items) |atom_index| { + const atom = elf_file.atom(atom_index) orelse continue; + if (!atom.flags.alive) continue; + const shdr = atom.inputShdr(elf_file); + if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (atom.scanRelocsRequiresCode(elf_file)) { + // TODO ideally we don't have to fetch the code here. + // Perhaps it would make sense to save the code until flushModule where we + // would free all of generated code? + const code = try self.codeAlloc(elf_file, atom_index); + defer elf_file.base.allocator.free(code); + try atom.scanRelocs(elf_file, code, undefs); + } else try atom.scanRelocs(elf_file, null, undefs); + } +} + +pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void { + for (self.globals()) |index| { + const global = elf_file.symbol(index); + const off = global.name_offset; + global.* = .{}; + global.name_offset = off; + } +} + +pub fn markLive(self: *ZigModule, elf_file: *Elf) void { + for (self.globals(), 0..) |index, i| { + const esym = self.global_esyms.items(.elf_sym)[i]; + if (esym.st_bind() == elf.STB_WEAK) continue; + + const global = elf_file.symbol(index); + const file = global.file(elf_file) orelse continue; + const should_keep = esym.st_shndx == elf.SHN_UNDEF or + (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON); + if (should_keep and !file.isAlive()) { + file.setAlive(); + file.markLive(elf_file); + } + } +} + +pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { + for (self.locals()) |local_index| { + const local = elf_file.symbol(local_index); + const esym = local.elfSym(elf_file); + switch (esym.st_type()) { + elf.STT_SECTION, elf.STT_NOTYPE => { + local.flags.output_symtab = false; + continue; + }, + else => {}, + } + local.flags.output_symtab = true; + self.output_symtab_size.nlocals += 1; + } + + for (self.globals()) |global_index| { + const global = elf_file.symbol(global_index); + if (global.file(elf_file)) |file| if (file.index() != self.index) { + global.flags.output_symtab = false; + continue; + }; + global.flags.output_symtab = true; + if (global.isLocal()) { + self.output_symtab_size.nlocals += 1; + } else { + self.output_symtab_size.nglobals += 1; + } + } +} + +pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void { + var ilocal = ctx.ilocal; + for (self.locals()) |local_index| { + const local = elf_file.symbol(local_index); + if (!local.flags.output_symtab) continue; + local.setOutputSym(elf_file, &ctx.symtab[ilocal]); + ilocal += 1; + } + + var iglobal = ctx.iglobal; + for (self.globals()) |global_index| { + const global = elf_file.symbol(global_index); + if (global.file(elf_file)) |file| if (file.index() != self.index) continue; + if (!global.flags.output_symtab) continue; + if (global.isLocal()) { + global.setOutputSym(elf_file, &ctx.symtab[ilocal]); + ilocal += 1; + } else { + global.setOutputSym(elf_file, &ctx.symtab[iglobal]); + iglobal += 1; + } + } +} + +pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index { + const is_global = index & global_symbol_bit != 0; + const actual_index = index & symbol_mask; + if (is_global) return self.global_symbols.items[actual_index]; + return self.local_symbols.items[actual_index]; +} + +pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym { + const is_global = index & global_symbol_bit != 0; + const actual_index = index & symbol_mask; + if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index]; + return &self.local_esyms.items(.elf_sym)[actual_index]; +} + +pub fn locals(self: *ZigModule) []const Symbol.Index { + return self.local_symbols.items; +} + +pub fn globals(self: *ZigModule) []const Symbol.Index { + return self.global_symbols.items; +} + +pub fn asFile(self: *ZigModule) File { + return .{ .zig_object = self }; +} + +/// Returns atom's code. +/// Caller owns the memory. +pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { + const gpa = elf_file.base.allocator; + const atom = elf_file.atom(atom_index).?; + assert(atom.file_index == self.index); + const shdr = &elf_file.shdrs.items[atom.outputShndx().?]; + const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr; + const size = std.math.cast(usize, atom.size) orelse return error.Overflow; + const code = try gpa.alloc(u8, size); + errdefer gpa.free(code); + const amt = try elf_file.base.file.?.preadAll(code, file_offset); + if (amt != code.len) { + log.err("fetching code for {s} failed", .{atom.name(elf_file)}); + return error.InputOutput; + } + return code; +} + +pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { + return .{ .data = .{ + .self = self, + .elf_file = elf_file, + } }; +} + +const FormatContext = struct { + self: *ZigModule, + elf_file: *Elf, +}; + +fn formatSymtab( + ctx: FormatContext, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = unused_fmt_string; + _ = options; + try writer.writeAll(" locals\n"); + for (ctx.self.locals()) |index| { + const local = ctx.elf_file.symbol(index); + try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); + } + try writer.writeAll(" globals\n"); + for (ctx.self.globals()) |index| { + const global = ctx.elf_file.symbol(index); + try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + } +} + +pub fn fmtAtoms(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatAtoms) { + return .{ .data = .{ + .self = self, + .elf_file = elf_file, + } }; +} + +fn formatAtoms( + ctx: FormatContext, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = unused_fmt_string; + _ = options; + try writer.writeAll(" atoms\n"); + for (ctx.self.atoms.items) |atom_index| { + const atom = ctx.elf_file.atom(atom_index) orelse continue; + try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)}); + } +} + +const ElfSym = struct { + elf_sym: elf.Elf64_Sym, + shndx: u32 = elf.SHN_UNDEF, +}; + +const assert = std.debug.assert; +const std = @import("std"); +const elf = std.elf; +const log = std.log.scoped(.link); + +const Allocator = std.mem.Allocator; +const Atom = @import("Atom.zig"); +const Elf = @import("../Elf.zig"); +const File = @import("file.zig").File; +const Module = @import("../../Module.zig"); +const Object = @import("Object.zig"); +const Symbol = @import("Symbol.zig"); +const ZigModule = @This(); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index f8258bb8847ca9a8a5e4d4b2ed29bf7ca88b6bf6..88620e2e5b101e2393ca639af2d8d29493d73cd0 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -1,5 +1,5 @@ pub const File = union(enum) { - zig_module: *ZigModule, + zig_object: *ZigObject, linker_defined: *LinkerDefined, object: *Object, shared_object: *SharedObject, @@ -23,7 +23,7 @@ pub const File = union(enum) { _ = unused_fmt_string; _ = options; switch (file) { - .zig_module => |x| try writer.print("{s}", .{x.path}), + .zig_object => |x| try writer.print("{s}", .{x.path}), .linker_defined => try writer.writeAll("(linker defined)"), .object => |x| try writer.print("{}", .{x.fmtPath()}), .shared_object => |x| try writer.writeAll(x.path), @@ -32,7 +32,7 @@ pub const File = union(enum) { pub fn isAlive(file: File) bool { return switch (file) { - .zig_module => true, + .zig_object => true, .linker_defined => true, inline else => |x| x.alive, }; @@ -76,7 +76,7 @@ pub const File = union(enum) { pub fn setAlive(file: File) void { switch (file) { - .zig_module, .linker_defined => {}, + .zig_object, .linker_defined => {}, inline else => |x| x.alive = true, } } @@ -92,7 +92,7 @@ pub const File = union(enum) { return switch (file) { .linker_defined => unreachable, .shared_object => unreachable, - .zig_module => |x| x.atoms.items, + .zig_object => |x| x.atoms.items, .object => |x| x.atoms.items, }; } @@ -115,7 +115,7 @@ pub const File = union(enum) { pub const Entry = union(enum) { null: void, - zig_module: ZigModule, + zig_object: ZigObject, linker_defined: LinkerDefined, object: Object, shared_object: SharedObject, @@ -132,4 +132,4 @@ const LinkerDefined = @import("LinkerDefined.zig"); const Object = @import("Object.zig"); const SharedObject = @import("SharedObject.zig"); const Symbol = @import("Symbol.zig"); -const ZigModule = @import("ZigModule.zig"); +const ZigObject = @import("ZigObject.zig");