| ... | ... | @@ -37,72 +37,87 @@ num_dynrelocs: u32 = 0, |
| 37 | 37 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| 38 | 38 | output_ar_state: Archive.ArState = .{}, |
| 39 | 39 | |
| 40 | | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 41 | | if (self.archive) |*ar| allocator.free(ar.path.sub_path); |
| 42 | | allocator.free(self.path.sub_path); |
| 43 | | self.shdrs.deinit(allocator); |
| 44 | | self.symtab.deinit(allocator); |
| 45 | | self.strtab.deinit(allocator); |
| 46 | | self.symbols.deinit(allocator); |
| 47 | | self.symbols_extra.deinit(allocator); |
| 48 | | self.symbols_resolver.deinit(allocator); |
| 49 | | self.atoms.deinit(allocator); |
| 50 | | self.atoms_indexes.deinit(allocator); |
| 51 | | self.atoms_extra.deinit(allocator); |
| 52 | | self.comdat_groups.deinit(allocator); |
| 53 | | self.comdat_group_data.deinit(allocator); |
| 54 | | self.relocs.deinit(allocator); |
| 55 | | self.fdes.deinit(allocator); |
| 56 | | self.cies.deinit(allocator); |
| 57 | | self.eh_frame_data.deinit(allocator); |
| 40 | pub fn deinit(self: *Object, gpa: Allocator) void { |
| 41 | if (self.archive) |*ar| gpa.free(ar.path.sub_path); |
| 42 | gpa.free(self.path.sub_path); |
| 43 | self.shdrs.deinit(gpa); |
| 44 | self.symtab.deinit(gpa); |
| 45 | self.strtab.deinit(gpa); |
| 46 | self.symbols.deinit(gpa); |
| 47 | self.symbols_extra.deinit(gpa); |
| 48 | self.symbols_resolver.deinit(gpa); |
| 49 | self.atoms.deinit(gpa); |
| 50 | self.atoms_indexes.deinit(gpa); |
| 51 | self.atoms_extra.deinit(gpa); |
| 52 | self.comdat_groups.deinit(gpa); |
| 53 | self.comdat_group_data.deinit(gpa); |
| 54 | self.relocs.deinit(gpa); |
| 55 | self.fdes.deinit(gpa); |
| 56 | self.cies.deinit(gpa); |
| 57 | self.eh_frame_data.deinit(gpa); |
| 58 | 58 | for (self.input_merge_sections.items) |*isec| { |
| 59 | | isec.deinit(allocator); |
| 59 | isec.deinit(gpa); |
| 60 | 60 | } |
| 61 | | self.input_merge_sections.deinit(allocator); |
| 62 | | self.input_merge_sections_indexes.deinit(allocator); |
| 61 | self.input_merge_sections.deinit(gpa); |
| 62 | self.input_merge_sections_indexes.deinit(gpa); |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | | pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 66 | | const gpa = elf_file.base.comp.gpa; |
| 67 | | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 68 | | const handle = elf_file.fileHandle(self.file_handle); |
| 69 | | |
| 70 | | try self.parseCommon(gpa, handle, elf_file); |
| 65 | pub fn parse( |
| 66 | self: *Object, |
| 67 | gpa: Allocator, |
| 68 | diags: *Diags, |
| 69 | /// For error reporting purposes only. |
| 70 | path: Path, |
| 71 | handle: fs.File, |
| 72 | first_eflags: *?elf.Word, |
| 73 | target: std.Target, |
| 74 | debug_fmt_strip: bool, |
| 75 | default_sym_version: elf.Versym, |
| 76 | ) !void { |
| 77 | try self.parseCommon(gpa, diags, path, handle, first_eflags, target); |
| 71 | 78 | |
| 72 | 79 | // Append null input merge section |
| 73 | 80 | try self.input_merge_sections.append(gpa, .{}); |
| 74 | 81 | // Allocate atom index 0 to null atom |
| 75 | 82 | try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); |
| 76 | 83 | |
| 77 | | try self.initAtoms(gpa, handle, elf_file); |
| 78 | | try self.initSymbols(gpa, elf_file); |
| 84 | try self.initAtoms(gpa, diags, path, handle, debug_fmt_strip, target); |
| 85 | try self.initSymbols(gpa, default_sym_version); |
| 79 | 86 | |
| 80 | 87 | for (self.shdrs.items, 0..) |shdr, i| { |
| 81 | 88 | const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue; |
| 82 | 89 | if (!atom_ptr.alive) continue; |
| 83 | | if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or |
| 84 | | mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) |
| 90 | if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or |
| 91 | mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame")) |
| 85 | 92 | { |
| 86 | | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); |
| 93 | try self.parseEhFrame(gpa, handle, @intCast(i), target); |
| 87 | 94 | } |
| 88 | 95 | } |
| 89 | 96 | } |
| 90 | 97 | |
| 91 | | fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { |
| 98 | fn parseCommon( |
| 99 | self: *Object, |
| 100 | gpa: Allocator, |
| 101 | diags: *Diags, |
| 102 | path: Path, |
| 103 | handle: fs.File, |
| 104 | first_eflags: *?elf.Word, |
| 105 | target: std.Target, |
| 106 | ) !void { |
| 92 | 107 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 93 | 108 | const file_size = (try handle.stat()).size; |
| 94 | 109 | |
| 95 | | const header_buffer = try Elf.preadAllAlloc(allocator, handle, offset, @sizeOf(elf.Elf64_Ehdr)); |
| 96 | | defer allocator.free(header_buffer); |
| 110 | const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr)); |
| 111 | defer gpa.free(header_buffer); |
| 97 | 112 | self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; |
| 98 | 113 | |
| 99 | | const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine(); |
| 114 | const em = target.toElfMachine(); |
| 100 | 115 | if (em != self.header.?.e_machine) { |
| 101 | | return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{ |
| 116 | return diags.failParse(path, "invalid ELF machine type: {s}", .{ |
| 102 | 117 | @tagName(self.header.?.e_machine), |
| 103 | 118 | }); |
| 104 | 119 | } |
| 105 | | try elf_file.validateEFlags(self.index, self.header.?.e_flags); |
| 120 | try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags); |
| 106 | 121 | |
| 107 | 122 | if (self.header.?.e_shnum == 0) return; |
| 108 | 123 | |
| ... | ... | @@ -110,30 +125,30 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 110 | 125 | const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; |
| 111 | 126 | const shsize = shnum * @sizeOf(elf.Elf64_Shdr); |
| 112 | 127 | if (file_size < offset + shoff or file_size < offset + shoff + shsize) { |
| 113 | | return elf_file.failFile(self.index, "corrupt header: section header table extends past the end of file", .{}); |
| 128 | return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{}); |
| 114 | 129 | } |
| 115 | 130 | |
| 116 | | const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize); |
| 117 | | defer allocator.free(shdrs_buffer); |
| 131 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize); |
| 132 | defer gpa.free(shdrs_buffer); |
| 118 | 133 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; |
| 119 | | try self.shdrs.appendUnalignedSlice(allocator, shdrs); |
| 134 | try self.shdrs.appendUnalignedSlice(gpa, shdrs); |
| 120 | 135 | |
| 121 | 136 | for (self.shdrs.items) |shdr| { |
| 122 | 137 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 123 | 138 | if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) { |
| 124 | | return elf_file.failFile(self.index, "corrupt section: extends past the end of file", .{}); |
| 139 | return diags.failParse(path, "corrupt section: extends past the end of file", .{}); |
| 125 | 140 | } |
| 126 | 141 | } |
| 127 | 142 | } |
| 128 | 143 | |
| 129 | | const shstrtab = try self.preadShdrContentsAlloc(allocator, handle, self.header.?.e_shstrndx); |
| 130 | | defer allocator.free(shstrtab); |
| 144 | const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx); |
| 145 | defer gpa.free(shstrtab); |
| 131 | 146 | for (self.shdrs.items) |shdr| { |
| 132 | 147 | if (shdr.sh_name >= shstrtab.len) { |
| 133 | | return elf_file.failFile(self.index, "corrupt section name offset", .{}); |
| 148 | return diags.failParse(path, "corrupt section name offset", .{}); |
| 134 | 149 | } |
| 135 | 150 | } |
| 136 | | try self.strtab.appendSlice(allocator, shstrtab); |
| 151 | try self.strtab.appendSlice(gpa, shstrtab); |
| 137 | 152 | |
| 138 | 153 | const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { |
| 139 | 154 | elf.SHT_SYMTAB => break @as(u32, @intCast(i)), |
| ... | ... | @@ -144,19 +159,19 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 144 | 159 | const shdr = self.shdrs.items[index]; |
| 145 | 160 | self.first_global = shdr.sh_info; |
| 146 | 161 | |
| 147 | | const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index); |
| 148 | | defer allocator.free(raw_symtab); |
| 162 | const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); |
| 163 | defer gpa.free(raw_symtab); |
| 149 | 164 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 150 | | return elf_file.failFile(self.index, "symbol table not evenly divisible", .{}); |
| 165 | return diags.failParse(path, "symbol table not evenly divisible", .{}); |
| 151 | 166 | }; |
| 152 | 167 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 153 | 168 | |
| 154 | 169 | const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); |
| 155 | | const strtab = try self.preadShdrContentsAlloc(allocator, handle, shdr.sh_link); |
| 156 | | defer allocator.free(strtab); |
| 157 | | try self.strtab.appendSlice(allocator, strtab); |
| 170 | const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link); |
| 171 | defer gpa.free(strtab); |
| 172 | try self.strtab.appendSlice(gpa, strtab); |
| 158 | 173 | |
| 159 | | try self.symtab.ensureUnusedCapacity(allocator, symtab.len); |
| 174 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); |
| 160 | 175 | for (symtab) |sym| { |
| 161 | 176 | const out_sym = self.symtab.addOneAssumeCapacity(); |
| 162 | 177 | out_sym.* = sym; |
| ... | ... | @@ -168,15 +183,56 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 168 | 183 | } |
| 169 | 184 | } |
| 170 | 185 | |
| 171 | | fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { |
| 172 | | const comp = elf_file.base.comp; |
| 173 | | const debug_fmt_strip = comp.config.debug_format == .strip; |
| 174 | | const target = comp.root_mod.resolved_target.result; |
| 186 | fn validateEFlags( |
| 187 | diags: *Diags, |
| 188 | path: Path, |
| 189 | target: std.Target, |
| 190 | e_flags: elf.Word, |
| 191 | first_eflags: *?elf.Word, |
| 192 | ) error{LinkFailure}!void { |
| 193 | if (first_eflags.*) |*self_eflags| { |
| 194 | switch (target.cpu.arch) { |
| 195 | .riscv64 => { |
| 196 | if (e_flags != self_eflags.*) { |
| 197 | const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags); |
| 198 | const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags); |
| 199 | |
| 200 | self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc; |
| 201 | self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso; |
| 202 | |
| 203 | var any_errors: bool = false; |
| 204 | if (self_riscv_eflags.fabi != riscv_eflags.fabi) { |
| 205 | any_errors = true; |
| 206 | diags.addParseError(path, "cannot link object files with different float-point ABIs", .{}); |
| 207 | } |
| 208 | if (self_riscv_eflags.rve != riscv_eflags.rve) { |
| 209 | any_errors = true; |
| 210 | diags.addParseError(path, "cannot link object files with different RVEs", .{}); |
| 211 | } |
| 212 | if (any_errors) return error.LinkFailure; |
| 213 | } |
| 214 | }, |
| 215 | else => {}, |
| 216 | } |
| 217 | } else { |
| 218 | first_eflags.* = e_flags; |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | fn initAtoms( |
| 223 | self: *Object, |
| 224 | gpa: Allocator, |
| 225 | diags: *Diags, |
| 226 | path: Path, |
| 227 | handle: fs.File, |
| 228 | debug_fmt_strip: bool, |
| 229 | target: std.Target, |
| 230 | ) !void { |
| 175 | 231 | const shdrs = self.shdrs.items; |
| 176 | | try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len); |
| 177 | | try self.atoms_extra.ensureTotalCapacityPrecise(allocator, shdrs.len * @sizeOf(Atom.Extra)); |
| 178 | | try self.atoms_indexes.ensureTotalCapacityPrecise(allocator, shdrs.len); |
| 179 | | try self.atoms_indexes.resize(allocator, shdrs.len); |
| 232 | try self.atoms.ensureTotalCapacityPrecise(gpa, shdrs.len); |
| 233 | try self.atoms_extra.ensureTotalCapacityPrecise(gpa, shdrs.len * @sizeOf(Atom.Extra)); |
| 234 | try self.atoms_indexes.ensureTotalCapacityPrecise(gpa, shdrs.len); |
| 235 | try self.atoms_indexes.resize(gpa, shdrs.len); |
| 180 | 236 | @memset(self.atoms_indexes.items, 0); |
| 181 | 237 | |
| 182 | 238 | for (shdrs, 0..) |shdr, i| { |
| ... | ... | @@ -201,24 +257,24 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 201 | 257 | }; |
| 202 | 258 | |
| 203 | 259 | const shndx: u32 = @intCast(i); |
| 204 | | const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 205 | | defer allocator.free(group_raw_data); |
| 260 | const group_raw_data = try self.preadShdrContentsAlloc(gpa, handle, shndx); |
| 261 | defer gpa.free(group_raw_data); |
| 206 | 262 | const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch { |
| 207 | | return elf_file.failFile(self.index, "corrupt section group: not evenly divisible ", .{}); |
| 263 | return diags.failParse(path, "corrupt section group: not evenly divisible ", .{}); |
| 208 | 264 | }; |
| 209 | 265 | if (group_nmembers == 0) { |
| 210 | | return elf_file.failFile(self.index, "corrupt section group: empty section", .{}); |
| 266 | return diags.failParse(path, "corrupt section group: empty section", .{}); |
| 211 | 267 | } |
| 212 | 268 | const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; |
| 213 | 269 | |
| 214 | 270 | if (group_members[0] != elf.GRP_COMDAT) { |
| 215 | | return elf_file.failFile(self.index, "corrupt section group: unknown SHT_GROUP format", .{}); |
| 271 | return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{}); |
| 216 | 272 | } |
| 217 | 273 | |
| 218 | 274 | const group_start: u32 = @intCast(self.comdat_group_data.items.len); |
| 219 | | try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]); |
| 275 | try self.comdat_group_data.appendUnalignedSlice(gpa, group_members[1..]); |
| 220 | 276 | |
| 221 | | const comdat_group_index = try self.addComdatGroup(allocator); |
| 277 | const comdat_group_index = try self.addComdatGroup(gpa); |
| 222 | 278 | const comdat_group = self.comdatGroup(comdat_group_index); |
| 223 | 279 | comdat_group.* = .{ |
| 224 | 280 | .signature_off = group_signature, |
| ... | ... | @@ -242,8 +298,8 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 242 | 298 | const shndx: u32 = @intCast(i); |
| 243 | 299 | if (self.skipShdr(shndx, debug_fmt_strip)) continue; |
| 244 | 300 | const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: { |
| 245 | | const data = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 246 | | defer allocator.free(data); |
| 301 | const data = try self.preadShdrContentsAlloc(gpa, handle, shndx); |
| 302 | defer gpa.free(data); |
| 247 | 303 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 248 | 304 | break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) }; |
| 249 | 305 | } else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) }; |
| ... | ... | @@ -263,13 +319,13 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 263 | 319 | elf.SHT_REL, elf.SHT_RELA => { |
| 264 | 320 | const atom_index = self.atoms_indexes.items[shdr.sh_info]; |
| 265 | 321 | if (self.atom(atom_index)) |atom_ptr| { |
| 266 | | const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); |
| 267 | | defer allocator.free(relocs); |
| 322 | const relocs = try self.preadRelocsAlloc(gpa, handle, @intCast(i)); |
| 323 | defer gpa.free(relocs); |
| 268 | 324 | atom_ptr.relocs_section_index = @intCast(i); |
| 269 | 325 | const rel_index: u32 = @intCast(self.relocs.items.len); |
| 270 | 326 | const rel_count: u32 = @intCast(relocs.len); |
| 271 | 327 | self.setAtomFields(atom_ptr, .{ .rel_index = rel_index, .rel_count = rel_count }); |
| 272 | | try self.relocs.appendUnalignedSlice(allocator, relocs); |
| 328 | try self.relocs.appendUnalignedSlice(gpa, relocs); |
| 273 | 329 | if (target.cpu.arch == .riscv64) { |
| 274 | 330 | sortRelocs(self.relocs.items[rel_index..][0..rel_count]); |
| 275 | 331 | } |
| ... | ... | @@ -293,14 +349,18 @@ fn skipShdr(self: *Object, index: u32, debug_fmt_strip: bool) bool { |
| 293 | 349 | return ignore; |
| 294 | 350 | } |
| 295 | 351 | |
| 296 | | fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 352 | fn initSymbols( |
| 353 | self: *Object, |
| 354 | gpa: Allocator, |
| 355 | default_sym_version: elf.Versym, |
| 356 | ) !void { |
| 297 | 357 | const first_global = self.first_global orelse self.symtab.items.len; |
| 298 | 358 | const nglobals = self.symtab.items.len - first_global; |
| 299 | 359 | |
| 300 | | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); |
| 301 | | try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra)); |
| 302 | | try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals); |
| 303 | | self.symbols_resolver.resize(allocator, nglobals) catch unreachable; |
| 360 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len); |
| 361 | try self.symbols_extra.ensureTotalCapacityPrecise(gpa, self.symtab.items.len * @sizeOf(Symbol.Extra)); |
| 362 | try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nglobals); |
| 363 | self.symbols_resolver.resize(gpa, nglobals) catch unreachable; |
| 304 | 364 | @memset(self.symbols_resolver.items, 0); |
| 305 | 365 | |
| 306 | 366 | for (self.symtab.items, 0..) |sym, i| { |
| ... | ... | @@ -310,7 +370,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 310 | 370 | sym_ptr.name_offset = sym.st_name; |
| 311 | 371 | sym_ptr.esym_index = @intCast(i); |
| 312 | 372 | sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{}); |
| 313 | | sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else .LOCAL; |
| 373 | sym_ptr.version_index = if (i >= first_global) default_sym_version else .LOCAL; |
| 314 | 374 | sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK; |
| 315 | 375 | if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { |
| 316 | 376 | sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; |
| ... | ... | @@ -318,24 +378,30 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 318 | 378 | } |
| 319 | 379 | } |
| 320 | 380 | |
| 321 | | fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { |
| 381 | fn parseEhFrame( |
| 382 | self: *Object, |
| 383 | gpa: Allocator, |
| 384 | handle: fs.File, |
| 385 | shndx: u32, |
| 386 | target: std.Target, |
| 387 | ) !void { |
| 322 | 388 | const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { |
| 323 | 389 | elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), |
| 324 | 390 | else => {}, |
| 325 | 391 | } else null; |
| 326 | 392 | |
| 327 | | const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 328 | | defer allocator.free(raw); |
| 329 | | const data_start = @as(u32, @intCast(self.eh_frame_data.items.len)); |
| 330 | | try self.eh_frame_data.appendSlice(allocator, raw); |
| 393 | const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx); |
| 394 | defer gpa.free(raw); |
| 395 | const data_start: u32 = @intCast(self.eh_frame_data.items.len); |
| 396 | try self.eh_frame_data.appendSlice(gpa, raw); |
| 331 | 397 | const relocs = if (relocs_shndx) |index| |
| 332 | | try self.preadRelocsAlloc(allocator, handle, index) |
| 398 | try self.preadRelocsAlloc(gpa, handle, index) |
| 333 | 399 | else |
| 334 | 400 | &[0]elf.Elf64_Rela{}; |
| 335 | | defer allocator.free(relocs); |
| 336 | | const rel_start = @as(u32, @intCast(self.relocs.items.len)); |
| 337 | | try self.relocs.appendUnalignedSlice(allocator, relocs); |
| 338 | | if (elf_file.getTarget().cpu.arch == .riscv64) { |
| 401 | defer gpa.free(relocs); |
| 402 | const rel_start: u32 = @intCast(self.relocs.items.len); |
| 403 | try self.relocs.appendUnalignedSlice(gpa, relocs); |
| 404 | if (target.cpu.arch == .riscv64) { |
| 339 | 405 | sortRelocs(self.relocs.items[rel_start..][0..relocs.len]); |
| 340 | 406 | } |
| 341 | 407 | const fdes_start = self.fdes.items.len; |
| ... | ... | @@ -345,11 +411,11 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 345 | 411 | while (try it.next()) |rec| { |
| 346 | 412 | const rel_range = filterRelocs(self.relocs.items[rel_start..][0..relocs.len], rec.offset, rec.size + 4); |
| 347 | 413 | switch (rec.tag) { |
| 348 | | .cie => try self.cies.append(allocator, .{ |
| 414 | .cie => try self.cies.append(gpa, .{ |
| 349 | 415 | .offset = data_start + rec.offset, |
| 350 | 416 | .size = rec.size, |
| 351 | 417 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), |
| 352 | | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 418 | .rel_num = @intCast(rel_range.len), |
| 353 | 419 | .input_section_index = shndx, |
| 354 | 420 | .file_index = self.index, |
| 355 | 421 | }), |
| ... | ... | @@ -361,12 +427,12 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 361 | 427 | // this can happen for object files built with -r flag by the linker. |
| 362 | 428 | continue; |
| 363 | 429 | } |
| 364 | | try self.fdes.append(allocator, .{ |
| 430 | try self.fdes.append(gpa, .{ |
| 365 | 431 | .offset = data_start + rec.offset, |
| 366 | 432 | .size = rec.size, |
| 367 | 433 | .cie_index = undefined, |
| 368 | 434 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), |
| 369 | | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 435 | .rel_num = @intCast(rel_range.len), |
| 370 | 436 | .input_section_index = shndx, |
| 371 | 437 | .file_index = self.index, |
| 372 | 438 | }); |
| ... | ... | @@ -376,7 +442,7 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 376 | 442 | |
| 377 | 443 | // Tie each FDE to its CIE |
| 378 | 444 | for (self.fdes.items[fdes_start..]) |*fde| { |
| 379 | | const cie_ptr = fde.offset + 4 - fde.ciePointer(elf_file); |
| 445 | const cie_ptr = fde.offset + 4 - fde.ciePointer(self); |
| 380 | 446 | const cie_index = for (self.cies.items[cies_start..], cies_start..) |cie, cie_index| { |
| 381 | 447 | if (cie.offset == cie_ptr) break @as(u32, @intCast(cie_index)); |
| 382 | 448 | } else { |
| ... | ... | @@ -392,26 +458,26 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 392 | 458 | |
| 393 | 459 | // Tie each FDE record to its matching atom |
| 394 | 460 | const SortFdes = struct { |
| 395 | | pub fn lessThan(ctx: *Elf, lhs: Fde, rhs: Fde) bool { |
| 461 | pub fn lessThan(ctx: *Object, lhs: Fde, rhs: Fde) bool { |
| 396 | 462 | const lhs_atom = lhs.atom(ctx); |
| 397 | 463 | const rhs_atom = rhs.atom(ctx); |
| 398 | | return lhs_atom.priority(ctx) < rhs_atom.priority(ctx); |
| 464 | return Atom.priorityLookup(ctx.index, lhs_atom.input_section_index) < Atom.priorityLookup(ctx.index, rhs_atom.input_section_index); |
| 399 | 465 | } |
| 400 | 466 | }; |
| 401 | | mem.sort(Fde, self.fdes.items[fdes_start..], elf_file, SortFdes.lessThan); |
| 467 | mem.sort(Fde, self.fdes.items[fdes_start..], self, SortFdes.lessThan); |
| 402 | 468 | |
| 403 | 469 | // Create a back-link from atom to FDEs |
| 404 | | var i: u32 = @as(u32, @intCast(fdes_start)); |
| 470 | var i: u32 = @intCast(fdes_start); |
| 405 | 471 | while (i < self.fdes.items.len) { |
| 406 | 472 | const fde = self.fdes.items[i]; |
| 407 | | const atom_ptr = fde.atom(elf_file); |
| 473 | const atom_ptr = fde.atom(self); |
| 408 | 474 | const start = i; |
| 409 | 475 | i += 1; |
| 410 | 476 | while (i < self.fdes.items.len) : (i += 1) { |
| 411 | 477 | const next_fde = self.fdes.items[i]; |
| 412 | | if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break; |
| 478 | if (atom_ptr.atom_index != next_fde.atom(self).atom_index) break; |
| 413 | 479 | } |
| 414 | | atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file); |
| 480 | self.setAtomFields(atom_ptr, .{ .fde_start = start, .fde_count = i - start }); |
| 415 | 481 | } |
| 416 | 482 | } |
| 417 | 483 | |
| ... | ... | @@ -904,7 +970,7 @@ pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void { |
| 904 | 970 | const atom_index = self.atoms_indexes.items[shndx]; |
| 905 | 971 | if (self.atom(atom_index)) |atom_ptr| { |
| 906 | 972 | atom_ptr.alive = false; |
| 907 | | atom_ptr.markFdesDead(elf_file); |
| 973 | atom_ptr.markFdesDead(self); |
| 908 | 974 | } |
| 909 | 975 | } |
| 910 | 976 | } |
| ... | ... | @@ -970,10 +1036,13 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void { |
| 970 | 1036 | } |
| 971 | 1037 | } |
| 972 | 1038 | |
| 973 | | pub fn parseAr(self: *Object, elf_file: *Elf) !void { |
| 1039 | pub fn parseAr(self: *Object, path: Path, elf_file: *Elf) !void { |
| 974 | 1040 | const gpa = elf_file.base.comp.gpa; |
| 1041 | const diags = &elf_file.base.comp.link_diags; |
| 975 | 1042 | const handle = elf_file.fileHandle(self.file_handle); |
| 976 | | try self.parseCommon(gpa, handle, elf_file); |
| 1043 | const first_eflags = &elf_file.first_eflags; |
| 1044 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| 1045 | try self.parseCommon(gpa, diags, path, handle, first_eflags, target); |
| 977 | 1046 | } |
| 978 | 1047 | |
| 979 | 1048 | pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { |
| ... | ... | @@ -1000,7 +1069,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void { |
| 1000 | 1069 | pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { |
| 1001 | 1070 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 1002 | 1071 | const offset: u64 = if (self.archive) |ar| ar.offset else 0; |
| 1003 | | const name = std.fs.path.basename(self.path.sub_path); |
| 1072 | const name = fs.path.basename(self.path.sub_path); |
| 1004 | 1073 | const hdr = Archive.setArHdr(.{ |
| 1005 | 1074 | .name = if (name.len <= Archive.max_member_name_len) |
| 1006 | 1075 | .{ .name = name } |
| ... | ... | @@ -1136,8 +1205,8 @@ pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref |
| 1136 | 1205 | return elf_file.resolver.get(resolv).?; |
| 1137 | 1206 | } |
| 1138 | 1207 | |
| 1139 | | fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { |
| 1140 | | try self.symbols.ensureUnusedCapacity(allocator, 1); |
| 1208 | fn addSymbol(self: *Object, gpa: Allocator) !Symbol.Index { |
| 1209 | try self.symbols.ensureUnusedCapacity(gpa, 1); |
| 1141 | 1210 | return self.addSymbolAssumeCapacity(); |
| 1142 | 1211 | } |
| 1143 | 1212 | |
| ... | ... | @@ -1147,9 +1216,9 @@ fn addSymbolAssumeCapacity(self: *Object) Symbol.Index { |
| 1147 | 1216 | return index; |
| 1148 | 1217 | } |
| 1149 | 1218 | |
| 1150 | | pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 { |
| 1219 | pub fn addSymbolExtra(self: *Object, gpa: Allocator, extra: Symbol.Extra) !u32 { |
| 1151 | 1220 | const fields = @typeInfo(Symbol.Extra).@"struct".fields; |
| 1152 | | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); |
| 1221 | try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len); |
| 1153 | 1222 | return self.addSymbolExtraAssumeCapacity(extra); |
| 1154 | 1223 | } |
| 1155 | 1224 | |
| ... | ... | @@ -1198,27 +1267,27 @@ pub fn getString(self: Object, off: u32) [:0]const u8 { |
| 1198 | 1267 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 1199 | 1268 | } |
| 1200 | 1269 | |
| 1201 | | fn addString(self: *Object, allocator: Allocator, str: []const u8) !u32 { |
| 1270 | fn addString(self: *Object, gpa: Allocator, str: []const u8) !u32 { |
| 1202 | 1271 | const off: u32 = @intCast(self.strtab.items.len); |
| 1203 | | try self.strtab.ensureUnusedCapacity(allocator, str.len + 1); |
| 1272 | try self.strtab.ensureUnusedCapacity(gpa, str.len + 1); |
| 1204 | 1273 | self.strtab.appendSliceAssumeCapacity(str); |
| 1205 | 1274 | self.strtab.appendAssumeCapacity(0); |
| 1206 | 1275 | return off; |
| 1207 | 1276 | } |
| 1208 | 1277 | |
| 1209 | 1278 | /// Caller owns the memory. |
| 1210 | | fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { |
| 1279 | fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: fs.File, index: u32) ![]u8 { |
| 1211 | 1280 | assert(index < self.shdrs.items.len); |
| 1212 | 1281 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1213 | 1282 | const shdr = self.shdrs.items[index]; |
| 1214 | 1283 | const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow; |
| 1215 | 1284 | const sh_size = math.cast(u64, shdr.sh_size) orelse return error.Overflow; |
| 1216 | | return Elf.preadAllAlloc(allocator, handle, offset + sh_offset, sh_size); |
| 1285 | return Elf.preadAllAlloc(gpa, handle, offset + sh_offset, sh_size); |
| 1217 | 1286 | } |
| 1218 | 1287 | |
| 1219 | 1288 | /// Caller owns the memory. |
| 1220 | | fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { |
| 1221 | | const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 1289 | fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { |
| 1290 | const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx); |
| 1222 | 1291 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); |
| 1223 | 1292 | return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; |
| 1224 | 1293 | } |
| ... | ... | @@ -1230,9 +1299,9 @@ const AddAtomArgs = struct { |
| 1230 | 1299 | alignment: Alignment, |
| 1231 | 1300 | }; |
| 1232 | 1301 | |
| 1233 | | fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index { |
| 1234 | | try self.atoms.ensureUnusedCapacity(allocator, 1); |
| 1235 | | try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra)); |
| 1302 | fn addAtom(self: *Object, gpa: Allocator, args: AddAtomArgs) !Atom.Index { |
| 1303 | try self.atoms.ensureUnusedCapacity(gpa, 1); |
| 1304 | try self.atoms_extra.ensureUnusedCapacity(gpa, @sizeOf(Atom.Extra)); |
| 1236 | 1305 | return self.addAtomAssumeCapacity(args); |
| 1237 | 1306 | } |
| 1238 | 1307 | |
| ... | ... | @@ -1257,9 +1326,9 @@ pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom { |
| 1257 | 1326 | return &self.atoms.items[atom_index]; |
| 1258 | 1327 | } |
| 1259 | 1328 | |
| 1260 | | pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 { |
| 1329 | pub fn addAtomExtra(self: *Object, gpa: Allocator, extra: Atom.Extra) !u32 { |
| 1261 | 1330 | const fields = @typeInfo(Atom.Extra).@"struct".fields; |
| 1262 | | try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len); |
| 1331 | try self.atoms_extra.ensureUnusedCapacity(gpa, fields.len); |
| 1263 | 1332 | return self.addAtomExtraAssumeCapacity(extra); |
| 1264 | 1333 | } |
| 1265 | 1334 | |
| ... | ... | @@ -1308,9 +1377,9 @@ fn setAtomFields(o: *Object, atom_ptr: *Atom, opts: Atom.Extra.AsOptionals) void |
| 1308 | 1377 | o.setAtomExtra(atom_ptr.extra_index, extras); |
| 1309 | 1378 | } |
| 1310 | 1379 | |
| 1311 | | fn addInputMergeSection(self: *Object, allocator: Allocator) !Merge.InputSection.Index { |
| 1380 | fn addInputMergeSection(self: *Object, gpa: Allocator) !Merge.InputSection.Index { |
| 1312 | 1381 | const index: Merge.InputSection.Index = @intCast(self.input_merge_sections.items.len); |
| 1313 | | const msec = try self.input_merge_sections.addOne(allocator); |
| 1382 | const msec = try self.input_merge_sections.addOne(gpa); |
| 1314 | 1383 | msec.* = .{}; |
| 1315 | 1384 | return index; |
| 1316 | 1385 | } |
| ... | ... | @@ -1320,9 +1389,9 @@ fn inputMergeSection(self: *Object, index: Merge.InputSection.Index) ?*Merge.Inp |
| 1320 | 1389 | return &self.input_merge_sections.items[index]; |
| 1321 | 1390 | } |
| 1322 | 1391 | |
| 1323 | | fn addComdatGroup(self: *Object, allocator: Allocator) !Elf.ComdatGroup.Index { |
| 1392 | fn addComdatGroup(self: *Object, gpa: Allocator) !Elf.ComdatGroup.Index { |
| 1324 | 1393 | const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len)); |
| 1325 | | _ = try self.comdat_groups.addOne(allocator); |
| 1394 | _ = try self.comdat_groups.addOne(gpa); |
| 1326 | 1395 | return index; |
| 1327 | 1396 | } |
| 1328 | 1397 | |
| ... | ... | @@ -1516,8 +1585,9 @@ const log = std.log.scoped(.link); |
| 1516 | 1585 | const math = std.math; |
| 1517 | 1586 | const mem = std.mem; |
| 1518 | 1587 | const Path = std.Build.Cache.Path; |
| 1519 | | const Allocator = mem.Allocator; |
| 1588 | const Allocator = std.mem.Allocator; |
| 1520 | 1589 | |
| 1590 | const Diags = @import("../../link.zig").Diags; |
| 1521 | 1591 | const Archive = @import("Archive.zig"); |
| 1522 | 1592 | const Atom = @import("Atom.zig"); |
| 1523 | 1593 | const AtomList = @import("AtomList.zig"); |
| ... | ... | @@ -1528,3 +1598,4 @@ const File = @import("file.zig").File; |
| 1528 | 1598 | const Merge = @import("Merge.zig"); |
| 1529 | 1599 | const Symbol = @import("Symbol.zig"); |
| 1530 | 1600 | const Alignment = Atom.Alignment; |
| 1601 | const riscv = @import("../riscv.zig"); |