diff --git a/src/link.zig b/src/link.zig index 8dfe3929a0..688210c355 100644 --- a/src/link.zig +++ b/src/link.zig @@ -2294,9 +2294,10 @@ fn resolvePathInputLib( const test_path: Path = pq.path; // In the case of shared libraries, they might actually be "linker scripts" // that contain references to other libraries. - if (pq.query.allow_so_scripts and target.ofmt == .elf and - Compilation.classifyFileExt(test_path.sub_path) == .shared_library) - { + if (pq.query.allow_so_scripts and target.ofmt == .elf and switch (Compilation.classifyFileExt(test_path.sub_path)) { + .static_library, .shared_library => true, + else => false, + }) { var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => return .no_match, else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ @@ -2304,14 +2305,13 @@ fn resolvePathInputLib( }), }; errdefer file.close(); - try ld_script_bytes.resize(gpa, @sizeOf(std.elf.Elf64_Ehdr)); + try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{'}': {s}", .{ test_path, @errorName(err), }); - elf_file: { - if (n != ld_script_bytes.items.len) break :elf_file; - if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file; - // Appears to be an ELF file. + const buf = ld_script_bytes.items[0..n]; + if (mem.startsWith(u8, buf, std.elf.MAGIC) or mem.startsWith(u8, buf, std.elf.ARMAG)) { + // Appears to be an ELF or archive file. return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); } const stat = file.stat() catch |err| @@ -2319,10 +2319,10 @@ fn resolvePathInputLib( const size = std.math.cast(u32, stat.size) orelse fatal("{}: linker script too big", .{test_path}); try ld_script_bytes.resize(gpa, size); - const buf = ld_script_bytes.items[n..]; - const n2 = file.preadAll(buf, n) catch |err| + const buf2 = ld_script_bytes.items[n..]; + const n2 = file.preadAll(buf2, n) catch |err| fatal("failed to read {}: {s}", .{ test_path, @errorName(err) }); - if (n2 != buf.len) fatal("failed to read {}: unexpected end of file", .{test_path}); + if (n2 != buf2.len) fatal("failed to read {}: unexpected end of file", .{test_path}); var diags = Diags.init(gpa); defer diags.deinit(); const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 41ecb4adc8..d947f1219b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -99,7 +99,7 @@ copy_rel: CopyRelSection = .{}, rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .empty, /// SHT_GROUP sections /// Applies only to a relocatable. -comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .empty, +group_sections: std.ArrayListUnmanaged(GroupSection) = .empty, resolver: SymbolResolver = .{}, @@ -510,7 +510,7 @@ pub fn deinit(self: *Elf) void { self.copy_rel.deinit(gpa); self.rela_dyn.deinit(gpa); self.rela_plt.deinit(gpa); - self.comdat_group_sections.deinit(gpa); + self.group_sections.deinit(gpa); self.dump_argv_list.deinit(gpa); } @@ -919,7 +919,7 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { &self.sections, self.shstrtab.items, self.merge_sections.items, - self.comdat_group_sections.items, + self.group_sections.items, self.zigObjectPtr(), self.files, ); @@ -1315,16 +1315,16 @@ pub fn resolveSymbols(self: *Elf) !void { } { - // Dedup comdat groups. + // Dedup groups. var table = std.StringHashMap(Ref).init(self.base.comp.gpa); defer table.deinit(); for (self.objects.items) |index| { - try self.file(index).?.object.resolveComdatGroups(self, &table); + try self.file(index).?.object.resolveGroups(self, &table); } for (self.objects.items) |index| { - self.file(index).?.object.markComdatGroupsDead(self); + self.file(index).?.object.markGroupsDead(self); } } @@ -3125,7 +3125,7 @@ pub fn sortShdrs( sections: *std.MultiArrayList(Section), shstrtab: []const u8, merge_sections: []Merge.Section, - comdat_group_sections: []ComdatGroupSection, + comdat_group_sections: []GroupSection, zig_object_ptr: ?*ZigObject, files: std.MultiArrayList(File.Entry), ) !void { @@ -4446,8 +4446,8 @@ pub fn atom(self: *Elf, ref: Ref) ?*Atom { return file_ptr.atom(ref.index); } -pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup { - return self.file(ref.file).?.comdatGroup(ref.index); +pub fn group(self: *Elf, ref: Ref) *Group { + return self.file(ref.file).?.group(ref.index); } pub fn symbol(self: *Elf, ref: Ref) ?*Symbol { @@ -4814,7 +4814,7 @@ fn fmtDumpState( object.fmtCies(self), object.fmtFdes(self), object.fmtSymtab(self), - object.fmtComdatGroups(self), + object.fmtGroups(self), }); } @@ -4852,9 +4852,9 @@ fn fmtDumpState( try writer.print("{}\n", .{self.got.fmt(self)}); try writer.print("{}\n", .{self.plt.fmt(self)}); - try writer.writeAll("Output COMDAT groups\n"); - for (self.comdat_group_sections.items) |cg| { - try writer.print(" shdr({d}) : COMDAT({})\n", .{ cg.shndx, cg.cg_ref }); + try writer.writeAll("Output groups\n"); + for (self.group_sections.items) |cg| { + try writer.print(" shdr({d}) : GROUP({})\n", .{ cg.shndx, cg.cg_ref }); } try writer.writeAll("\nOutput merge sections\n"); @@ -4934,25 +4934,26 @@ const default_entry_addr = 0x8000000; pub const base_tag: link.File.Tag = .elf; -pub const ComdatGroup = struct { +pub const Group = struct { signature_off: u32, file_index: File.Index, shndx: u32, members_start: u32, members_len: u32, + is_comdat: bool, alive: bool = true, - pub fn file(cg: ComdatGroup, elf_file: *Elf) File { + pub fn file(cg: Group, elf_file: *Elf) File { return elf_file.file(cg.file_index).?; } - pub fn signature(cg: ComdatGroup, elf_file: *Elf) [:0]const u8 { + pub fn signature(cg: Group, elf_file: *Elf) [:0]const u8 { return cg.file(elf_file).object.getString(cg.signature_off); } - pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 { + pub fn members(cg: Group, elf_file: *Elf) []const u32 { const object = cg.file(elf_file).object; - return object.comdat_group_data.items[cg.members_start..][0..cg.members_len]; + return object.group_data.items[cg.members_start..][0..cg.members_len]; } pub const Index = u32; @@ -5310,7 +5311,7 @@ const Air = @import("../Air.zig"); const Archive = @import("Elf/Archive.zig"); const AtomList = @import("Elf/AtomList.zig"); const Compilation = @import("../Compilation.zig"); -const ComdatGroupSection = synthetic_sections.ComdatGroupSection; +const GroupSection = synthetic_sections.GroupSection; const CopyRelSection = synthetic_sections.CopyRelSection; const Diags = @import("../link.zig").Diags; const DynamicSection = synthetic_sections.DynamicSection; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 2597553544..dcea9fe402 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -20,8 +20,8 @@ atoms: std.ArrayListUnmanaged(Atom) = .empty, atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .empty, atoms_extra: std.ArrayListUnmanaged(u32) = .empty, -comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .empty, -comdat_group_data: std.ArrayListUnmanaged(u32) = .empty, +groups: std.ArrayListUnmanaged(Elf.Group) = .empty, +group_data: std.ArrayListUnmanaged(u32) = .empty, input_merge_sections: std.ArrayListUnmanaged(Merge.InputSection) = .empty, input_merge_sections_indexes: std.ArrayListUnmanaged(Merge.InputSection.Index) = .empty, @@ -49,8 +49,8 @@ pub fn deinit(self: *Object, gpa: Allocator) void { self.atoms.deinit(gpa); self.atoms_indexes.deinit(gpa); self.atoms_extra.deinit(gpa); - self.comdat_groups.deinit(gpa); - self.comdat_group_data.deinit(gpa); + self.groups.deinit(gpa); + self.group_data.deinit(gpa); self.relocs.deinit(gpa); self.fdes.deinit(gpa); self.cies.deinit(gpa); @@ -304,22 +304,22 @@ fn initAtoms( } const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; - if (group_members[0] != elf.GRP_COMDAT) { - return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{}); + switch (group_members[0]) { + 0, elf.GRP_COMDAT => { + const group_start: u32 = @intCast(self.group_data.items.len); + try self.group_data.appendUnalignedSlice(gpa, group_members[1..]); + + self.group(try self.addGroup(gpa)).* = .{ + .signature_off = group_signature, + .file_index = self.index, + .shndx = shndx, + .members_start = group_start, + .members_len = @intCast(group_nmembers - 1), + .is_comdat = group_members[0] == elf.GRP_COMDAT, + }; + }, + else => return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{}), } - - const group_start: u32 = @intCast(self.comdat_group_data.items.len); - try self.comdat_group_data.appendUnalignedSlice(gpa, group_members[1..]); - - const comdat_group_index = try self.addComdatGroup(gpa); - const comdat_group = self.comdatGroup(comdat_group_index); - comdat_group.* = .{ - .signature_off = group_signature, - .file_index = self.index, - .shndx = shndx, - .members_start = group_start, - .members_len = @intCast(group_nmembers - 1), - }; }, elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), @@ -986,28 +986,28 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { } } -pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void { - for (self.comdat_groups.items, 0..) |*cg, cgi| { - const signature = cg.signature(elf_file); +pub fn resolveGroups(self: *Object, elf_file: *Elf, table: anytype) !void { + for (self.groups.items, 0..) |*g, gi| { + const signature = g.signature(elf_file); const gop = try table.getOrPut(signature); if (!gop.found_existing) { - gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index }; + gop.value_ptr.* = .{ .index = @intCast(gi), .file = self.index }; continue; } - const current = elf_file.comdatGroup(gop.value_ptr.*); - cg.alive = false; + const current = elf_file.group(gop.value_ptr.*); + g.alive = false; if (self.index < current.file_index) { current.alive = false; - cg.alive = true; - gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index }; + g.alive = true; + gop.value_ptr.* = .{ .index = @intCast(gi), .file = self.index }; } } } -pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void { - for (self.comdat_groups.items) |cg| { - if (cg.alive) continue; - for (cg.comdatGroupMembers(elf_file)) |shndx| { +pub fn markGroupsDead(self: *Object, elf_file: *Elf) void { + for (self.groups.items) |g| { + if (g.alive) continue; + for (g.members(elf_file)) |shndx| { const atom_index = self.atoms_indexes.items[shndx]; if (self.atom(atom_index)) |atom_ptr| { atom_ptr.alive = false; @@ -1421,15 +1421,15 @@ fn inputMergeSection(self: *Object, index: Merge.InputSection.Index) ?*Merge.Inp return &self.input_merge_sections.items[index]; } -fn addComdatGroup(self: *Object, gpa: Allocator) !Elf.ComdatGroup.Index { - const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len)); - _ = try self.comdat_groups.addOne(gpa); +fn addGroup(self: *Object, gpa: Allocator) !Elf.Group.Index { + const index: Elf.Group.Index = @intCast(self.groups.items.len); + _ = try self.groups.addOne(gpa); return index; } -pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup { - assert(index < self.comdat_groups.items.len); - return &self.comdat_groups.items[index]; +pub fn group(self: *Object, index: Elf.Group.Index) *Elf.Group { + assert(index < self.groups.items.len); + return &self.groups.items[index]; } pub fn format( @@ -1550,14 +1550,14 @@ fn formatFdes( } } -pub fn fmtComdatGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatComdatGroups) { +pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatGroups) { return .{ .data = .{ .object = self, .elf_file = elf_file, } }; } -fn formatComdatGroups( +fn formatGroups( ctx: FormatContext, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, @@ -1567,13 +1567,13 @@ fn formatComdatGroups( _ = options; const object = ctx.object; const elf_file = ctx.elf_file; - try writer.writeAll(" COMDAT groups\n"); - for (object.comdat_groups.items, 0..) |cg, cg_index| { - try writer.print(" COMDAT({d})", .{cg_index}); - if (!cg.alive) try writer.writeAll(" : [*]"); + try writer.writeAll(" groups\n"); + for (object.groups.items, 0..) |g, g_index| { + try writer.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index }); + if (!g.alive) try writer.writeAll(" : [*]"); try writer.writeByte('\n'); - const cg_members = cg.comdatGroupMembers(elf_file); - for (cg_members) |shndx| { + const g_members = g.members(elf_file); + for (g_members) |shndx| { const atom_index = object.atoms_indexes.items[shndx]; const atom_ptr = object.atom(atom_index) orelse continue; try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) }); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index e560644329..7292f8ca5d 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -198,10 +198,10 @@ pub const File = union(enum) { }; } - pub fn comdatGroup(file: File, ind: Elf.ComdatGroup.Index) *Elf.ComdatGroup { + pub fn group(file: File, ind: Elf.Group.Index) *Elf.Group { return switch (file) { .linker_defined, .shared_object, .zig_object => unreachable, - .object => |x| x.comdatGroup(ind), + .object => |x| x.group(ind), }; } diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index a33717d2d1..6541364f92 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -19,7 +19,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { &elf_file.sections, elf_file.shstrtab.items, elf_file.merge_sections.items, - elf_file.comdat_group_sections.items, + elf_file.group_sections.items, elf_file.zigObjectPtr(), elf_file.files, ); @@ -152,7 +152,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void { &elf_file.sections, elf_file.shstrtab.items, elf_file.merge_sections.items, - elf_file.comdat_group_sections.items, + elf_file.group_sections.items, elf_file.zigObjectPtr(), elf_file.files, ); @@ -233,19 +233,19 @@ fn initSections(elf_file: *Elf) !void { ); } - try initComdatGroups(elf_file); + try initGroups(elf_file); try elf_file.initSymtab(); try elf_file.initShStrtab(); } -fn initComdatGroups(elf_file: *Elf) !void { +fn initGroups(elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; - for (object.comdat_groups.items, 0..) |cg, cg_index| { + for (object.groups.items, 0..) |cg, cg_index| { if (!cg.alive) continue; - const cg_sec = try elf_file.comdat_group_sections.addOne(gpa); + const cg_sec = try elf_file.group_sections.addOne(gpa); cg_sec.* = .{ .shndx = try elf_file.addSection(.{ .name = try elf_file.insertShString(".group"), @@ -292,12 +292,12 @@ fn updateSectionSizes(elf_file: *Elf) !void { } try elf_file.updateSymtabSize(); - updateComdatGroupsSizes(elf_file); + updateGroupsSizes(elf_file); elf_file.updateShStrtabSize(); } -fn updateComdatGroupsSizes(elf_file: *Elf) void { - for (elf_file.comdat_group_sections.items) |cg| { +fn updateGroupsSizes(elf_file: *Elf) void { + for (elf_file.group_sections.items) |cg| { const shdr = &elf_file.sections.items(.shdr)[cg.shndx]; shdr.sh_size = cg.size(elf_file); shdr.sh_link = elf_file.section_indexes.symtab.?; @@ -436,21 +436,21 @@ fn writeSyntheticSections(elf_file: *Elf) !void { try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); } - try writeComdatGroups(elf_file); + try writeGroups(elf_file); try elf_file.writeSymtab(); try elf_file.writeShStrtab(); } -fn writeComdatGroups(elf_file: *Elf) !void { +fn writeGroups(elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; - for (elf_file.comdat_group_sections.items) |cgs| { + for (elf_file.group_sections.items) |cgs| { const shdr = elf_file.sections.items(.shdr)[cgs.shndx]; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); defer buffer.deinit(); try cgs.write(elf_file, buffer.writer()); assert(buffer.items.len == sh_size); - log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{ + log.debug("writing group from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size, }); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 8364846019..aca0c17d0c 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1484,33 +1484,33 @@ pub const VerneedSection = struct { } }; -pub const ComdatGroupSection = struct { +pub const GroupSection = struct { shndx: u32, cg_ref: Elf.Ref, - fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup { + fn group(cgs: GroupSection, elf_file: *Elf) *Elf.Group { const cg_file = elf_file.file(cgs.cg_ref.file).?; - return cg_file.object.comdatGroup(cgs.cg_ref.index); + return cg_file.object.group(cgs.cg_ref.index); } - pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol { - const cg = cgs.comdatGroup(elf_file); + pub fn symbol(cgs: GroupSection, elf_file: *Elf) *Symbol { + const cg = cgs.group(elf_file); const object = cg.file(elf_file).object; const shdr = object.shdrs.items[cg.shndx]; return &object.symbols.items[shdr.sh_info]; } - pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { - const cg = cgs.comdatGroup(elf_file); - const members = cg.comdatGroupMembers(elf_file); + pub fn size(cgs: GroupSection, elf_file: *Elf) usize { + const cg = cgs.group(elf_file); + const members = cg.members(elf_file); return (members.len + 1) * @sizeOf(u32); } - pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { - const cg = cgs.comdatGroup(elf_file); + pub fn write(cgs: GroupSection, elf_file: *Elf, writer: anytype) !void { + const cg = cgs.group(elf_file); const object = cg.file(elf_file).object; - const members = cg.comdatGroupMembers(elf_file); - try writer.writeInt(u32, elf.GRP_COMDAT, .little); + const members = cg.members(elf_file); + try writer.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little); for (members) |shndx| { const shdr = object.shdrs.items[shndx]; switch (shdr.sh_type) {