| author | |
| committer | |
| log | eb5d67b146da7af693bc45f61e69070b0d6b27bb |
| tree | 7543827e786486810b5173cb6ece5714b04843b2 |
| parent | 082e5091af38acd0669f6ca14e13dee1ce65e509 |
link/elf: implement string merging18 files changed, 1368 insertions(+), 343 deletions(-)
src/link/Elf.zig+305-32| ... | @@ -205,10 +205,19 @@ num_ifunc_dynrelocs: usize = 0, | ... | @@ -205,10 +205,19 @@ num_ifunc_dynrelocs: usize = 0, |
| 205 | 205 | ||
| 206 | /// List of atoms that are owned directly by the linker. | 206 | /// List of atoms that are owned directly by the linker. |
| 207 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | 207 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 208 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | ||
| 208 | 209 | ||
| 209 | /// List of range extension thunks. | 210 | /// List of range extension thunks. |
| 210 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, | 211 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, |
| 211 | 212 | ||
| 213 | /// List of output merge sections with deduped contents. | ||
| 214 | merge_sections: std.ArrayListUnmanaged(MergeSection) = .{}, | ||
| 215 | /// List of output merge subsections. | ||
| 216 | /// Each subsection is akin to Atom but belongs to a MergeSection. | ||
| 217 | merge_subsections: std.ArrayListUnmanaged(MergeSubsection) = .{}, | ||
| 218 | /// List of input merge sections as parsed from input relocatables. | ||
| 219 | merge_input_sections: std.ArrayListUnmanaged(InputMergeSection) = .{}, | ||
| 220 | |||
| 212 | /// Table of last atom index in a section and matching atom free list if any. | 221 | /// Table of last atom index in a section and matching atom free list if any. |
| 213 | last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, | 222 | last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, |
| 214 | 223 | ||
| ... | @@ -369,6 +378,7 @@ pub fn createEmpty( | ... | @@ -369,6 +378,7 @@ pub fn createEmpty( |
| 369 | try self.symbols_extra.append(gpa, 0); | 378 | try self.symbols_extra.append(gpa, 0); |
| 370 | // Allocate atom index 0 to null atom | 379 | // Allocate atom index 0 to null atom |
| 371 | try self.atoms.append(gpa, .{}); | 380 | try self.atoms.append(gpa, .{}); |
| 381 | try self.atoms_extra.append(gpa, 0); | ||
| 372 | // Append null file at index 0 | 382 | // Append null file at index 0 |
| 373 | try self.files.append(gpa, .null); | 383 | try self.files.append(gpa, .null); |
| 374 | // Append null byte to string tables | 384 | // Append null byte to string tables |
| ... | @@ -378,6 +388,8 @@ pub fn createEmpty( | ... | @@ -378,6 +388,8 @@ pub fn createEmpty( |
| 378 | _ = try self.addSection(.{ .name = "" }); | 388 | _ = try self.addSection(.{ .name = "" }); |
| 379 | // Append null symbol in output symtab | 389 | // Append null symbol in output symtab |
| 380 | try self.symtab.append(gpa, null_sym); | 390 | try self.symtab.append(gpa, null_sym); |
| 391 | // Append null input merge section. | ||
| 392 | try self.merge_input_sections.append(gpa, .{}); | ||
| 381 | 393 | ||
| 382 | if (!is_obj_or_ar) { | 394 | if (!is_obj_or_ar) { |
| 383 | try self.dynstrtab.append(gpa, 0); | 395 | try self.dynstrtab.append(gpa, 0); |
| ... | @@ -491,7 +503,20 @@ pub fn deinit(self: *Elf) void { | ... | @@ -491,7 +503,20 @@ pub fn deinit(self: *Elf) void { |
| 491 | self.start_stop_indexes.deinit(gpa); | 503 | self.start_stop_indexes.deinit(gpa); |
| 492 | 504 | ||
| 493 | self.atoms.deinit(gpa); | 505 | self.atoms.deinit(gpa); |
| 506 | self.atoms_extra.deinit(gpa); | ||
| 507 | for (self.thunks.items) |*th| { | ||
| 508 | th.deinit(gpa); | ||
| 509 | } | ||
| 494 | self.thunks.deinit(gpa); | 510 | self.thunks.deinit(gpa); |
| 511 | for (self.merge_sections.items) |*sect| { | ||
| 512 | sect.deinit(gpa); | ||
| 513 | } | ||
| 514 | self.merge_sections.deinit(gpa); | ||
| 515 | self.merge_subsections.deinit(gpa); | ||
| 516 | for (self.merge_input_sections.items) |*sect| { | ||
| 517 | sect.deinit(gpa); | ||
| 518 | } | ||
| 519 | self.merge_input_sections.deinit(gpa); | ||
| 495 | for (self.last_atom_and_free_list_table.values()) |*value| { | 520 | for (self.last_atom_and_free_list_table.values()) |*value| { |
| 496 | value.free_list.deinit(gpa); | 521 | value.free_list.deinit(gpa); |
| 497 | } | 522 | } |
| ... | @@ -1289,6 +1314,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1289,6 +1314,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1289 | // symbol for potential resolution at load-time. | 1314 | // symbol for potential resolution at load-time. |
| 1290 | self.resolveSymbols(); | 1315 | self.resolveSymbols(); |
| 1291 | self.markEhFrameAtomsDead(); | 1316 | self.markEhFrameAtomsDead(); |
| 1317 | try self.resolveMergeSections(); | ||
| 1292 | 1318 | ||
| 1293 | try self.convertCommonSymbols(); | 1319 | try self.convertCommonSymbols(); |
| 1294 | self.markImportsExports(); | 1320 | self.markImportsExports(); |
| ... | @@ -1313,7 +1339,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1313,7 +1339,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1313 | else => |e| return e, | 1339 | else => |e| return e, |
| 1314 | }; | 1340 | }; |
| 1315 | 1341 | ||
| 1342 | try self.addCommentString(); | ||
| 1343 | try self.finalizeMergeSections(); | ||
| 1316 | try self.initOutputSections(); | 1344 | try self.initOutputSections(); |
| 1345 | try self.initMergeSections(); | ||
| 1317 | try self.addLinkerDefinedSymbols(); | 1346 | try self.addLinkerDefinedSymbols(); |
| 1318 | self.claimUnresolved(); | 1347 | self.claimUnresolved(); |
| 1319 | 1348 | ||
| ... | @@ -1332,6 +1361,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1332,6 +1361,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1332 | self.sortDynamicSymtab(); | 1361 | self.sortDynamicSymtab(); |
| 1333 | try self.setHashSections(); | 1362 | try self.setHashSections(); |
| 1334 | try self.setVersionSymtab(); | 1363 | try self.setVersionSymtab(); |
| 1364 | try self.updateMergeSectionSizes(); | ||
| 1335 | try self.updateSectionSizes(); | 1365 | try self.updateSectionSizes(); |
| 1336 | 1366 | ||
| 1337 | try self.allocatePhdrTable(); | 1367 | try self.allocatePhdrTable(); |
| ... | @@ -1359,7 +1389,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1359,7 +1389,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1359 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | 1389 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1360 | const code = try zig_object.codeAlloc(self, atom_index); | 1390 | const code = try zig_object.codeAlloc(self, atom_index); |
| 1361 | defer gpa.free(code); | 1391 | defer gpa.free(code); |
| 1362 | const file_offset = shdr.sh_offset + atom_ptr.value; | 1392 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1363 | atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { | 1393 | atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { |
| 1364 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, | 1394 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, |
| 1365 | error.UnsupportedCpuArch => { | 1395 | error.UnsupportedCpuArch => { |
| ... | @@ -1377,6 +1407,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1377,6 +1407,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1377 | try self.writePhdrTable(); | 1407 | try self.writePhdrTable(); |
| 1378 | try self.writeShdrTable(); | 1408 | try self.writeShdrTable(); |
| 1379 | try self.writeAtoms(); | 1409 | try self.writeAtoms(); |
| 1410 | try self.writeMergeSections(); | ||
| 1380 | self.writeSyntheticSections() catch |err| switch (err) { | 1411 | self.writeSyntheticSections() catch |err| switch (err) { |
| 1381 | error.RelocFailure => return error.FlushFailure, | 1412 | error.RelocFailure => return error.FlushFailure, |
| 1382 | error.UnsupportedCpuArch => { | 1413 | error.UnsupportedCpuArch => { |
| ... | @@ -2946,7 +2977,10 @@ pub fn writeElfHeader(self: *Elf) !void { | ... | @@ -2946,7 +2977,10 @@ pub fn writeElfHeader(self: *Elf) !void { |
| 2946 | mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); | 2977 | mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); |
| 2947 | index += 4; | 2978 | index += 4; |
| 2948 | 2979 | ||
| 2949 | const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).address(.{}, self) else 0; | 2980 | const e_entry = if (self.entry_index) |entry_index| |
| 2981 | @as(u64, @intCast(self.symbol(entry_index).address(.{}, self))) | ||
| 2982 | else | ||
| 2983 | 0; | ||
| 2950 | const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0; | 2984 | const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0; |
| 2951 | switch (self.ptr_width) { | 2985 | switch (self.ptr_width) { |
| 2952 | .p32 => { | 2986 | .p32 => { |
| ... | @@ -3132,14 +3166,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3132,14 +3166,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3132 | if (self.dynamic_section_index) |shndx| { | 3166 | if (self.dynamic_section_index) |shndx| { |
| 3133 | const shdr = &self.shdrs.items[shndx]; | 3167 | const shdr = &self.shdrs.items[shndx]; |
| 3134 | const symbol_ptr = self.symbol(self.dynamic_index.?); | 3168 | const symbol_ptr = self.symbol(self.dynamic_index.?); |
| 3135 | symbol_ptr.value = shdr.sh_addr; | 3169 | symbol_ptr.value = @intCast(shdr.sh_addr); |
| 3136 | symbol_ptr.output_section_index = shndx; | 3170 | symbol_ptr.output_section_index = shndx; |
| 3137 | } | 3171 | } |
| 3138 | 3172 | ||
| 3139 | // __ehdr_start | 3173 | // __ehdr_start |
| 3140 | { | 3174 | { |
| 3141 | const symbol_ptr = self.symbol(self.ehdr_start_index.?); | 3175 | const symbol_ptr = self.symbol(self.ehdr_start_index.?); |
| 3142 | symbol_ptr.value = self.image_base; | 3176 | symbol_ptr.value = @intCast(self.image_base); |
| 3143 | symbol_ptr.output_section_index = 1; | 3177 | symbol_ptr.output_section_index = 1; |
| 3144 | } | 3178 | } |
| 3145 | 3179 | ||
| ... | @@ -3149,9 +3183,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3149,9 +3183,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3149 | const end_sym = self.symbol(self.init_array_end_index.?); | 3183 | const end_sym = self.symbol(self.init_array_end_index.?); |
| 3150 | const shdr = &self.shdrs.items[shndx]; | 3184 | const shdr = &self.shdrs.items[shndx]; |
| 3151 | start_sym.output_section_index = shndx; | 3185 | start_sym.output_section_index = shndx; |
| 3152 | start_sym.value = shdr.sh_addr; | 3186 | start_sym.value = @intCast(shdr.sh_addr); |
| 3153 | end_sym.output_section_index = shndx; | 3187 | end_sym.output_section_index = shndx; |
| 3154 | end_sym.value = shdr.sh_addr + shdr.sh_size; | 3188 | end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); |
| 3155 | } | 3189 | } |
| 3156 | 3190 | ||
| 3157 | // __fini_array_start, __fini_array_end | 3191 | // __fini_array_start, __fini_array_end |
| ... | @@ -3160,9 +3194,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3160,9 +3194,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3160 | const end_sym = self.symbol(self.fini_array_end_index.?); | 3194 | const end_sym = self.symbol(self.fini_array_end_index.?); |
| 3161 | const shdr = &self.shdrs.items[shndx]; | 3195 | const shdr = &self.shdrs.items[shndx]; |
| 3162 | start_sym.output_section_index = shndx; | 3196 | start_sym.output_section_index = shndx; |
| 3163 | start_sym.value = shdr.sh_addr; | 3197 | start_sym.value = @intCast(shdr.sh_addr); |
| 3164 | end_sym.output_section_index = shndx; | 3198 | end_sym.output_section_index = shndx; |
| 3165 | end_sym.value = shdr.sh_addr + shdr.sh_size; | 3199 | end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); |
| 3166 | } | 3200 | } |
| 3167 | 3201 | ||
| 3168 | // __preinit_array_start, __preinit_array_end | 3202 | // __preinit_array_start, __preinit_array_end |
| ... | @@ -3171,9 +3205,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3171,9 +3205,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3171 | const end_sym = self.symbol(self.preinit_array_end_index.?); | 3205 | const end_sym = self.symbol(self.preinit_array_end_index.?); |
| 3172 | const shdr = &self.shdrs.items[shndx]; | 3206 | const shdr = &self.shdrs.items[shndx]; |
| 3173 | start_sym.output_section_index = shndx; | 3207 | start_sym.output_section_index = shndx; |
| 3174 | start_sym.value = shdr.sh_addr; | 3208 | start_sym.value = @intCast(shdr.sh_addr); |
| 3175 | end_sym.output_section_index = shndx; | 3209 | end_sym.output_section_index = shndx; |
| 3176 | end_sym.value = shdr.sh_addr + shdr.sh_size; | 3210 | end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); |
| 3177 | } | 3211 | } |
| 3178 | 3212 | ||
| 3179 | // _GLOBAL_OFFSET_TABLE_ | 3213 | // _GLOBAL_OFFSET_TABLE_ |
| ... | @@ -3181,14 +3215,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3181,14 +3215,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3181 | if (self.got_plt_section_index) |shndx| { | 3215 | if (self.got_plt_section_index) |shndx| { |
| 3182 | const shdr = self.shdrs.items[shndx]; | 3216 | const shdr = self.shdrs.items[shndx]; |
| 3183 | const sym = self.symbol(self.got_index.?); | 3217 | const sym = self.symbol(self.got_index.?); |
| 3184 | sym.value = shdr.sh_addr; | 3218 | sym.value = @intCast(shdr.sh_addr); |
| 3185 | sym.output_section_index = shndx; | 3219 | sym.output_section_index = shndx; |
| 3186 | } | 3220 | } |
| 3187 | } else { | 3221 | } else { |
| 3188 | if (self.got_section_index) |shndx| { | 3222 | if (self.got_section_index) |shndx| { |
| 3189 | const shdr = self.shdrs.items[shndx]; | 3223 | const shdr = self.shdrs.items[shndx]; |
| 3190 | const sym = self.symbol(self.got_index.?); | 3224 | const sym = self.symbol(self.got_index.?); |
| 3191 | sym.value = shdr.sh_addr; | 3225 | sym.value = @intCast(shdr.sh_addr); |
| 3192 | sym.output_section_index = shndx; | 3226 | sym.output_section_index = shndx; |
| 3193 | } | 3227 | } |
| 3194 | } | 3228 | } |
| ... | @@ -3197,7 +3231,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3197,7 +3231,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3197 | if (self.plt_section_index) |shndx| { | 3231 | if (self.plt_section_index) |shndx| { |
| 3198 | const shdr = &self.shdrs.items[shndx]; | 3232 | const shdr = &self.shdrs.items[shndx]; |
| 3199 | const symbol_ptr = self.symbol(self.plt_index.?); | 3233 | const symbol_ptr = self.symbol(self.plt_index.?); |
| 3200 | symbol_ptr.value = shdr.sh_addr; | 3234 | symbol_ptr.value = @intCast(shdr.sh_addr); |
| 3201 | symbol_ptr.output_section_index = shndx; | 3235 | symbol_ptr.output_section_index = shndx; |
| 3202 | } | 3236 | } |
| 3203 | 3237 | ||
| ... | @@ -3205,7 +3239,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3205,7 +3239,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3205 | if (self.dso_handle_index) |index| { | 3239 | if (self.dso_handle_index) |index| { |
| 3206 | const shdr = &self.shdrs.items[1]; | 3240 | const shdr = &self.shdrs.items[1]; |
| 3207 | const symbol_ptr = self.symbol(index); | 3241 | const symbol_ptr = self.symbol(index); |
| 3208 | symbol_ptr.value = shdr.sh_addr; | 3242 | symbol_ptr.value = @intCast(shdr.sh_addr); |
| 3209 | symbol_ptr.output_section_index = 0; | 3243 | symbol_ptr.output_section_index = 0; |
| 3210 | } | 3244 | } |
| 3211 | 3245 | ||
| ... | @@ -3213,7 +3247,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3213,7 +3247,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3213 | if (self.eh_frame_hdr_section_index) |shndx| { | 3247 | if (self.eh_frame_hdr_section_index) |shndx| { |
| 3214 | const shdr = &self.shdrs.items[shndx]; | 3248 | const shdr = &self.shdrs.items[shndx]; |
| 3215 | const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?); | 3249 | const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?); |
| 3216 | symbol_ptr.value = shdr.sh_addr; | 3250 | symbol_ptr.value = @intCast(shdr.sh_addr); |
| 3217 | symbol_ptr.output_section_index = shndx; | 3251 | symbol_ptr.output_section_index = shndx; |
| 3218 | } | 3252 | } |
| 3219 | 3253 | ||
| ... | @@ -3225,9 +3259,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3225,9 +3259,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3225 | const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); | 3259 | const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); |
| 3226 | const start_sym = self.symbol(self.rela_iplt_start_index.?); | 3260 | const start_sym = self.symbol(self.rela_iplt_start_index.?); |
| 3227 | const end_sym = self.symbol(self.rela_iplt_end_index.?); | 3261 | const end_sym = self.symbol(self.rela_iplt_end_index.?); |
| 3228 | start_sym.value = start_addr; | 3262 | start_sym.value = @intCast(start_addr); |
| 3229 | start_sym.output_section_index = shndx; | 3263 | start_sym.output_section_index = shndx; |
| 3230 | end_sym.value = end_addr; | 3264 | end_sym.value = @intCast(end_addr); |
| 3231 | end_sym.output_section_index = shndx; | 3265 | end_sym.output_section_index = shndx; |
| 3232 | } | 3266 | } |
| 3233 | 3267 | ||
| ... | @@ -3236,7 +3270,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3236,7 +3270,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3236 | const end_symbol = self.symbol(self.end_index.?); | 3270 | const end_symbol = self.symbol(self.end_index.?); |
| 3237 | for (self.shdrs.items, 0..) |shdr, shndx| { | 3271 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 3238 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) { | 3272 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) { |
| 3239 | end_symbol.value = shdr.sh_addr + shdr.sh_size; | 3273 | end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size); |
| 3240 | end_symbol.output_section_index = @intCast(shndx); | 3274 | end_symbol.output_section_index = @intCast(shndx); |
| 3241 | } | 3275 | } |
| 3242 | } | 3276 | } |
| ... | @@ -3251,9 +3285,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3251,9 +3285,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3251 | const stop = self.symbol(self.start_stop_indexes.items[index + 1]); | 3285 | const stop = self.symbol(self.start_stop_indexes.items[index + 1]); |
| 3252 | const shndx = self.sectionByName(name["__start_".len..]).?; | 3286 | const shndx = self.sectionByName(name["__start_".len..]).?; |
| 3253 | const shdr = &self.shdrs.items[shndx]; | 3287 | const shdr = &self.shdrs.items[shndx]; |
| 3254 | start.value = shdr.sh_addr; | 3288 | start.value = @intCast(shdr.sh_addr); |
| 3255 | start.output_section_index = shndx; | 3289 | start.output_section_index = shndx; |
| 3256 | stop.value = shdr.sh_addr + shdr.sh_size; | 3290 | stop.value = @intCast(shdr.sh_addr + shdr.sh_size); |
| 3257 | stop.output_section_index = shndx; | 3291 | stop.output_section_index = shndx; |
| 3258 | } | 3292 | } |
| 3259 | } | 3293 | } |
| ... | @@ -3263,7 +3297,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3263,7 +3297,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3263 | const sym = self.symbol(index); | 3297 | const sym = self.symbol(index); |
| 3264 | if (self.sectionByName(".sdata")) |shndx| { | 3298 | if (self.sectionByName(".sdata")) |shndx| { |
| 3265 | const shdr = self.shdrs.items[shndx]; | 3299 | const shdr = self.shdrs.items[shndx]; |
| 3266 | sym.value = shdr.sh_addr + 0x800; | 3300 | sym.value = @intCast(shdr.sh_addr + 0x800); |
| 3267 | sym.output_section_index = shndx; | 3301 | sym.output_section_index = shndx; |
| 3268 | } else { | 3302 | } else { |
| 3269 | sym.value = 0; | 3303 | sym.value = 0; |
| ... | @@ -3293,12 +3327,122 @@ fn checkDuplicates(self: *Elf) !void { | ... | @@ -3293,12 +3327,122 @@ fn checkDuplicates(self: *Elf) !void { |
| 3293 | try self.reportDuplicates(dupes); | 3327 | try self.reportDuplicates(dupes); |
| 3294 | } | 3328 | } |
| 3295 | 3329 | ||
| 3330 | pub fn addCommentString(self: *Elf) !void { | ||
| 3331 | const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, elf.SHT_PROGBITS); | ||
| 3332 | const msec = self.mergeSection(msec_index); | ||
| 3333 | const res = try msec.insertZ(self.base.comp.gpa, "zig " ++ builtin.zig_version_string); | ||
| 3334 | if (res.found_existing) return; | ||
| 3335 | const msub_index = try self.addMergeSubsection(); | ||
| 3336 | const msub = self.mergeSubsection(msub_index); | ||
| 3337 | msub.merge_section_index = msec_index; | ||
| 3338 | msub.string_index = res.key.pos; | ||
| 3339 | msub.alignment = .@"1"; | ||
| 3340 | msub.size = res.key.len; | ||
| 3341 | msub.entsize = 1; | ||
| 3342 | msub.alive = true; | ||
| 3343 | res.sub.* = msub_index; | ||
| 3344 | } | ||
| 3345 | |||
| 3346 | pub fn resolveMergeSections(self: *Elf) !void { | ||
| 3347 | const tracy = trace(@src()); | ||
| 3348 | defer tracy.end(); | ||
| 3349 | |||
| 3350 | var has_errors = false; | ||
| 3351 | for (self.objects.items) |index| { | ||
| 3352 | const file_ptr = self.file(index).?; | ||
| 3353 | if (!file_ptr.isAlive()) continue; | ||
| 3354 | file_ptr.object.initMergeSections(self) catch |err| switch (err) { | ||
| 3355 | error.MalformedObject => has_errors = true, | ||
| 3356 | else => |e| return e, | ||
| 3357 | }; | ||
| 3358 | } | ||
| 3359 | |||
| 3360 | if (has_errors) return error.FlushFailure; | ||
| 3361 | |||
| 3362 | for (self.objects.items) |index| { | ||
| 3363 | const file_ptr = self.file(index).?; | ||
| 3364 | if (!file_ptr.isAlive()) continue; | ||
| 3365 | file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) { | ||
| 3366 | error.MalformedObject => has_errors = true, | ||
| 3367 | else => |e| return e, | ||
| 3368 | }; | ||
| 3369 | } | ||
| 3370 | |||
| 3371 | if (has_errors) return error.FlushFailure; | ||
| 3372 | } | ||
| 3373 | |||
| 3374 | pub fn finalizeMergeSections(self: *Elf) !void { | ||
| 3375 | for (self.merge_sections.items) |*msec| { | ||
| 3376 | try msec.finalize(self); | ||
| 3377 | } | ||
| 3378 | } | ||
| 3379 | |||
| 3380 | pub fn updateMergeSectionSizes(self: *Elf) !void { | ||
| 3381 | for (self.merge_sections.items) |*msec| { | ||
| 3382 | const shdr = &self.shdrs.items[msec.output_section_index]; | ||
| 3383 | for (msec.subsections.items) |msub_index| { | ||
| 3384 | const msub = self.mergeSubsection(msub_index); | ||
| 3385 | assert(msub.alive); | ||
| 3386 | const offset = msub.alignment.forward(shdr.sh_size); | ||
| 3387 | const padding = offset - shdr.sh_size; | ||
| 3388 | msub.value = @intCast(offset); | ||
| 3389 | shdr.sh_size += padding + msub.size; | ||
| 3390 | shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1); | ||
| 3391 | } | ||
| 3392 | } | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | pub fn writeMergeSections(self: *Elf) !void { | ||
| 3396 | const gpa = self.base.comp.gpa; | ||
| 3397 | var buffer = std.ArrayList(u8).init(gpa); | ||
| 3398 | defer buffer.deinit(); | ||
| 3399 | |||
| 3400 | for (self.merge_sections.items) |msec| { | ||
| 3401 | const shdr = self.shdrs.items[msec.output_section_index]; | ||
| 3402 | const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 3403 | try buffer.ensureTotalCapacity(size); | ||
| 3404 | buffer.appendNTimesAssumeCapacity(0, size); | ||
| 3405 | |||
| 3406 | for (msec.subsections.items) |msub_index| { | ||
| 3407 | const msub = self.mergeSubsection(msub_index); | ||
| 3408 | assert(msub.alive); | ||
| 3409 | const string = msub.getString(self); | ||
| 3410 | const off = math.cast(usize, msub.value) orelse return error.Overflow; | ||
| 3411 | @memcpy(buffer.items[off..][0..string.len], string); | ||
| 3412 | } | ||
| 3413 | |||
| 3414 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 3415 | buffer.clearRetainingCapacity(); | ||
| 3416 | } | ||
| 3417 | } | ||
| 3418 | |||
| 3296 | fn initOutputSections(self: *Elf) !void { | 3419 | fn initOutputSections(self: *Elf) !void { |
| 3297 | for (self.objects.items) |index| { | 3420 | for (self.objects.items) |index| { |
| 3298 | try self.file(index).?.object.initOutputSections(self); | 3421 | try self.file(index).?.object.initOutputSections(self); |
| 3299 | } | 3422 | } |
| 3300 | } | 3423 | } |
| 3301 | 3424 | ||
| 3425 | pub fn initMergeSections(self: *Elf) !void { | ||
| 3426 | for (self.merge_sections.items) |*msec| { | ||
| 3427 | if (msec.subsections.items.len == 0) continue; | ||
| 3428 | const name = msec.name(self); | ||
| 3429 | const shndx = self.sectionByName(name) orelse try self.addSection(.{ | ||
| 3430 | .name = name, | ||
| 3431 | .type = msec.type, | ||
| 3432 | .flags = msec.flags, | ||
| 3433 | }); | ||
| 3434 | msec.output_section_index = shndx; | ||
| 3435 | |||
| 3436 | var entsize = self.mergeSubsection(msec.subsections.items[0]).entsize; | ||
| 3437 | for (msec.subsections.items) |index| { | ||
| 3438 | const msub = self.mergeSubsection(index); | ||
| 3439 | entsize = @min(entsize, msub.entsize); | ||
| 3440 | } | ||
| 3441 | const shdr = &self.shdrs.items[shndx]; | ||
| 3442 | shdr.sh_entsize = entsize; | ||
| 3443 | } | ||
| 3444 | } | ||
| 3445 | |||
| 3302 | fn initSyntheticSections(self: *Elf) !void { | 3446 | fn initSyntheticSections(self: *Elf) !void { |
| 3303 | const comp = self.base.comp; | 3447 | const comp = self.base.comp; |
| 3304 | const target = comp.root_mod.resolved_target.result; | 3448 | const target = comp.root_mod.resolved_target.result; |
| ... | @@ -3965,6 +4109,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void { | ... | @@ -3965,6 +4109,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void { |
| 3965 | } | 4109 | } |
| 3966 | } | 4110 | } |
| 3967 | 4111 | ||
| 4112 | for (self.merge_sections.items) |*msec| { | ||
| 4113 | msec.output_section_index = backlinks[msec.output_section_index]; | ||
| 4114 | } | ||
| 4115 | |||
| 3968 | { | 4116 | { |
| 3969 | var output_rela_sections = try self.output_rela_sections.clone(gpa); | 4117 | var output_rela_sections = try self.output_rela_sections.clone(gpa); |
| 3970 | defer output_rela_sections.deinit(gpa); | 4118 | defer output_rela_sections.deinit(gpa); |
| ... | @@ -4052,7 +4200,7 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -4052,7 +4200,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4052 | if (!atom_ptr.flags.alive) continue; | 4200 | if (!atom_ptr.flags.alive) continue; |
| 4053 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | 4201 | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 4054 | const padding = offset - shdr.sh_size; | 4202 | const padding = offset - shdr.sh_size; |
| 4055 | atom_ptr.value = offset; | 4203 | atom_ptr.value = @intCast(offset); |
| 4056 | shdr.sh_size += padding + atom_ptr.size; | 4204 | shdr.sh_size += padding + atom_ptr.size; |
| 4057 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); | 4205 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); |
| 4058 | } | 4206 | } |
| ... | @@ -4535,7 +4683,7 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4535,7 +4683,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4535 | const atom_ptr = self.atom(atom_index).?; | 4683 | const atom_ptr = self.atom(atom_index).?; |
| 4536 | assert(atom_ptr.flags.alive); | 4684 | assert(atom_ptr.flags.alive); |
| 4537 | 4685 | ||
| 4538 | const offset = math.cast(usize, atom_ptr.value - base_offset) orelse | 4686 | const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse |
| 4539 | return error.Overflow; | 4687 | return error.Overflow; |
| 4540 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 4688 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 4541 | 4689 | ||
| ... | @@ -4576,7 +4724,7 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4576,7 +4724,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4576 | const thunk_size = th.size(self); | 4724 | const thunk_size = th.size(self); |
| 4577 | try buffer.ensureUnusedCapacity(thunk_size); | 4725 | try buffer.ensureUnusedCapacity(thunk_size); |
| 4578 | const shdr = self.shdrs.items[th.output_section_index]; | 4726 | const shdr = self.shdrs.items[th.output_section_index]; |
| 4579 | const offset = th.value + shdr.sh_offset; | 4727 | const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; |
| 4580 | try th.write(self, buffer.writer()); | 4728 | try th.write(self, buffer.writer()); |
| 4581 | assert(buffer.items.len == thunk_size); | 4729 | assert(buffer.items.len == thunk_size); |
| 4582 | try self.base.file.?.pwriteAll(buffer.items, offset); | 4730 | try self.base.file.?.pwriteAll(buffer.items, offset); |
| ... | @@ -4611,6 +4759,7 @@ pub fn updateSymtabSize(self: *Elf) !void { | ... | @@ -4611,6 +4759,7 @@ pub fn updateSymtabSize(self: *Elf) !void { |
| 4611 | if (self.eh_frame_section_index) |_| { | 4759 | if (self.eh_frame_section_index) |_| { |
| 4612 | nlocals += 1; | 4760 | nlocals += 1; |
| 4613 | } | 4761 | } |
| 4762 | nlocals += @intCast(self.merge_sections.items.len); | ||
| 4614 | 4763 | ||
| 4615 | if (self.requiresThunks()) for (self.thunks.items) |*th| { | 4764 | if (self.requiresThunks()) for (self.thunks.items) |*th| { |
| 4616 | th.output_symtab_ctx.ilocal = nlocals + 1; | 4765 | th.output_symtab_ctx.ilocal = nlocals + 1; |
| ... | @@ -4947,12 +5096,30 @@ fn writeSectionSymbols(self: *Elf) void { | ... | @@ -4947,12 +5096,30 @@ fn writeSectionSymbols(self: *Elf) void { |
| 4947 | }; | 5096 | }; |
| 4948 | ilocal += 1; | 5097 | ilocal += 1; |
| 4949 | } | 5098 | } |
| 5099 | |||
| 5100 | for (self.merge_sections.items) |msec| { | ||
| 5101 | const shdr = self.shdrs.items[msec.output_section_index]; | ||
| 5102 | const out_sym = &self.symtab.items[ilocal]; | ||
| 5103 | out_sym.* = .{ | ||
| 5104 | .st_name = 0, | ||
| 5105 | .st_value = shdr.sh_addr, | ||
| 5106 | .st_info = elf.STT_SECTION, | ||
| 5107 | .st_shndx = @intCast(msec.output_section_index), | ||
| 5108 | .st_size = 0, | ||
| 5109 | .st_other = 0, | ||
| 5110 | }; | ||
| 5111 | ilocal += 1; | ||
| 5112 | } | ||
| 4950 | } | 5113 | } |
| 4951 | 5114 | ||
| 4952 | pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { | 5115 | pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 4953 | if (self.eh_frame_section_index) |index| { | 5116 | if (self.eh_frame_section_index) |index| { |
| 4954 | if (index == shndx) return @intCast(self.output_sections.keys().len + 1); | 5117 | if (index == shndx) return @intCast(self.output_sections.keys().len + 1); |
| 4955 | } | 5118 | } |
| 5119 | const base: usize = if (self.eh_frame_section_index == null) 0 else 1; | ||
| 5120 | for (self.merge_sections.items, 0..) |msec, index| { | ||
| 5121 | if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base); | ||
| 5122 | } | ||
| 4956 | return @intCast(self.output_sections.getIndex(shndx).? + 1); | 5123 | return @intCast(self.output_sections.getIndex(shndx).? + 1); |
| 4957 | } | 5124 | } |
| 4958 | 5125 | ||
| ... | @@ -5458,6 +5625,50 @@ pub fn addAtom(self: *Elf) !Atom.Index { | ... | @@ -5458,6 +5625,50 @@ pub fn addAtom(self: *Elf) !Atom.Index { |
| 5458 | return index; | 5625 | return index; |
| 5459 | } | 5626 | } |
| 5460 | 5627 | ||
| 5628 | pub fn addAtomExtra(self: *Elf, extra: Atom.Extra) !u32 { | ||
| 5629 | const fields = @typeInfo(Atom.Extra).Struct.fields; | ||
| 5630 | try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len); | ||
| 5631 | return self.addAtomExtraAssumeCapacity(extra); | ||
| 5632 | } | ||
| 5633 | |||
| 5634 | pub fn addAtomExtraAssumeCapacity(self: *Elf, extra: Atom.Extra) u32 { | ||
| 5635 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | ||
| 5636 | const fields = @typeInfo(Atom.Extra).Struct.fields; | ||
| 5637 | inline for (fields) |field| { | ||
| 5638 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | ||
| 5639 | u32 => @field(extra, field.name), | ||
| 5640 | else => @compileError("bad field type"), | ||
| 5641 | }); | ||
| 5642 | } | ||
| 5643 | return index; | ||
| 5644 | } | ||
| 5645 | |||
| 5646 | pub fn atomExtra(self: *Elf, index: u32) ?Atom.Extra { | ||
| 5647 | if (index == 0) return null; | ||
| 5648 | const fields = @typeInfo(Atom.Extra).Struct.fields; | ||
| 5649 | var i: usize = index; | ||
| 5650 | var result: Atom.Extra = undefined; | ||
| 5651 | inline for (fields) |field| { | ||
| 5652 | @field(result, field.name) = switch (field.type) { | ||
| 5653 | u32 => self.atoms_extra.items[i], | ||
| 5654 | else => @compileError("bad field type"), | ||
| 5655 | }; | ||
| 5656 | i += 1; | ||
| 5657 | } | ||
| 5658 | return result; | ||
| 5659 | } | ||
| 5660 | |||
| 5661 | pub fn setAtomExtra(self: *Elf, index: u32, extra: Atom.Extra) void { | ||
| 5662 | assert(index > 0); | ||
| 5663 | const fields = @typeInfo(Atom.Extra).Struct.fields; | ||
| 5664 | inline for (fields, 0..) |field, i| { | ||
| 5665 | self.atoms_extra.items[index + i] = switch (field.type) { | ||
| 5666 | u32 => @field(extra, field.name), | ||
| 5667 | else => @compileError("bad field type"), | ||
| 5668 | }; | ||
| 5669 | } | ||
| 5670 | } | ||
| 5671 | |||
| 5461 | pub fn addThunk(self: *Elf) !Thunk.Index { | 5672 | pub fn addThunk(self: *Elf) !Thunk.Index { |
| 5462 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); | 5673 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); |
| 5463 | const th = try self.thunks.addOne(self.base.comp.gpa); | 5674 | const th = try self.thunks.addOne(self.base.comp.gpa); |
| ... | @@ -5637,35 +5848,88 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO | ... | @@ -5637,35 +5848,88 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO |
| 5637 | return &self.comdat_groups_owners.items[index]; | 5848 | return &self.comdat_groups_owners.items[index]; |
| 5638 | } | 5849 | } |
| 5639 | 5850 | ||
| 5640 | pub fn gotAddress(self: *Elf) u64 { | 5851 | pub fn addInputMergeSection(self: *Elf) !InputMergeSection.Index { |
| 5852 | const index: InputMergeSection.Index = @intCast(self.merge_input_sections.items.len); | ||
| 5853 | const msec = try self.merge_input_sections.addOne(self.base.comp.gpa); | ||
| 5854 | msec.* = .{}; | ||
| 5855 | return index; | ||
| 5856 | } | ||
| 5857 | |||
| 5858 | pub fn inputMergeSection(self: *Elf, index: InputMergeSection.Index) ?*InputMergeSection { | ||
| 5859 | if (index == 0) return null; | ||
| 5860 | return &self.merge_input_sections.items[index]; | ||
| 5861 | } | ||
| 5862 | |||
| 5863 | pub fn addMergeSubsection(self: *Elf) !MergeSubsection.Index { | ||
| 5864 | const index: MergeSubsection.Index = @intCast(self.merge_subsections.items.len); | ||
| 5865 | const msec = try self.merge_subsections.addOne(self.base.comp.gpa); | ||
| 5866 | msec.* = .{}; | ||
| 5867 | return index; | ||
| 5868 | } | ||
| 5869 | |||
| 5870 | pub fn mergeSubsection(self: *Elf, index: MergeSubsection.Index) *MergeSubsection { | ||
| 5871 | assert(index < self.merge_subsections.items.len); | ||
| 5872 | return &self.merge_subsections.items[index]; | ||
| 5873 | } | ||
| 5874 | |||
| 5875 | pub fn getOrCreateMergeSection(self: *Elf, name: []const u8, flags: u64, @"type": u32) !MergeSection.Index { | ||
| 5876 | const gpa = self.base.comp.gpa; | ||
| 5877 | const out_name = name: { | ||
| 5878 | if (self.base.isRelocatable()) break :name name; | ||
| 5879 | if (mem.eql(u8, name, ".rodata") or mem.startsWith(u8, name, ".rodata")) | ||
| 5880 | break :name if (flags & elf.SHF_STRINGS != 0) ".rodata.str" else ".rodata.cst"; | ||
| 5881 | break :name name; | ||
| 5882 | }; | ||
| 5883 | const out_off = try self.strings.insert(gpa, out_name); | ||
| 5884 | const out_flags = flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP); | ||
| 5885 | for (self.merge_sections.items, 0..) |msec, index| { | ||
| 5886 | if (msec.name_offset == out_off) return @intCast(index); | ||
| 5887 | } | ||
| 5888 | const index = @as(MergeSection.Index, @intCast(self.merge_sections.items.len)); | ||
| 5889 | const msec = try self.merge_sections.addOne(gpa); | ||
| 5890 | msec.* = .{ | ||
| 5891 | .name_offset = out_off, | ||
| 5892 | .flags = out_flags, | ||
| 5893 | .type = @"type", | ||
| 5894 | }; | ||
| 5895 | return index; | ||
| 5896 | } | ||
| 5897 | |||
| 5898 | pub fn mergeSection(self: *Elf, index: MergeSection.Index) *MergeSection { | ||
| 5899 | assert(index < self.merge_sections.items.len); | ||
| 5900 | return &self.merge_sections.items[index]; | ||
| 5901 | } | ||
| 5902 | |||
| 5903 | pub fn gotAddress(self: *Elf) i64 { | ||
| 5641 | const shndx = blk: { | 5904 | const shndx = blk: { |
| 5642 | if (self.getTarget().cpu.arch == .x86_64 and self.got_plt_section_index != null) | 5905 | if (self.getTarget().cpu.arch == .x86_64 and self.got_plt_section_index != null) |
| 5643 | break :blk self.got_plt_section_index.?; | 5906 | break :blk self.got_plt_section_index.?; |
| 5644 | break :blk if (self.got_section_index) |shndx| shndx else null; | 5907 | break :blk if (self.got_section_index) |shndx| shndx else null; |
| 5645 | }; | 5908 | }; |
| 5646 | return if (shndx) |index| self.shdrs.items[index].sh_addr else 0; | 5909 | return if (shndx) |index| @intCast(self.shdrs.items[index].sh_addr) else 0; |
| 5647 | } | 5910 | } |
| 5648 | 5911 | ||
| 5649 | pub fn tpAddress(self: *Elf) u64 { | 5912 | pub fn tpAddress(self: *Elf) i64 { |
| 5650 | const index = self.phdr_tls_index orelse return 0; | 5913 | const index = self.phdr_tls_index orelse return 0; |
| 5651 | const phdr = self.phdrs.items[index]; | 5914 | const phdr = self.phdrs.items[index]; |
| 5652 | return switch (self.getTarget().cpu.arch) { | 5915 | const addr = switch (self.getTarget().cpu.arch) { |
| 5653 | .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), | 5916 | .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), |
| 5654 | .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), | 5917 | .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), |
| 5655 | else => @panic("TODO implement getTpAddress for this arch"), | 5918 | else => @panic("TODO implement getTpAddress for this arch"), |
| 5656 | }; | 5919 | }; |
| 5920 | return @intCast(addr); | ||
| 5657 | } | 5921 | } |
| 5658 | 5922 | ||
| 5659 | pub fn dtpAddress(self: *Elf) u64 { | 5923 | pub fn dtpAddress(self: *Elf) i64 { |
| 5660 | const index = self.phdr_tls_index orelse return 0; | 5924 | const index = self.phdr_tls_index orelse return 0; |
| 5661 | const phdr = self.phdrs.items[index]; | 5925 | const phdr = self.phdrs.items[index]; |
| 5662 | return phdr.p_vaddr; | 5926 | return @intCast(phdr.p_vaddr); |
| 5663 | } | 5927 | } |
| 5664 | 5928 | ||
| 5665 | pub fn tlsAddress(self: *Elf) u64 { | 5929 | pub fn tlsAddress(self: *Elf) i64 { |
| 5666 | const index = self.phdr_tls_index orelse return 0; | 5930 | const index = self.phdr_tls_index orelse return 0; |
| 5667 | const phdr = self.phdrs.items[index]; | 5931 | const phdr = self.phdrs.items[index]; |
| 5668 | return phdr.p_vaddr; | 5932 | return @intCast(phdr.p_vaddr); |
| 5669 | } | 5933 | } |
| 5670 | 5934 | ||
| 5671 | const ErrorWithNotes = struct { | 5935 | const ErrorWithNotes = struct { |
| ... | @@ -6043,6 +6307,11 @@ fn fmtDumpState( | ... | @@ -6043,6 +6307,11 @@ fn fmtDumpState( |
| 6043 | try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index }); | 6307 | try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index }); |
| 6044 | } | 6308 | } |
| 6045 | 6309 | ||
| 6310 | try writer.writeAll("\nOutput merge sections\n"); | ||
| 6311 | for (self.merge_sections.items) |msec| { | ||
| 6312 | try writer.print(" shdr({d}) : {}\n", .{ msec.output_section_index, msec.fmt(self) }); | ||
| 6313 | } | ||
| 6314 | |||
| 6046 | try writer.writeAll("\nOutput shdrs\n"); | 6315 | try writer.writeAll("\nOutput shdrs\n"); |
| 6047 | for (self.shdrs.items, 0..) |shdr, shndx| { | 6316 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 6048 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ | 6317 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ |
| ... | @@ -6235,6 +6504,7 @@ const gc = @import("Elf/gc.zig"); | ... | @@ -6235,6 +6504,7 @@ const gc = @import("Elf/gc.zig"); |
| 6235 | const glibc = @import("../glibc.zig"); | 6504 | const glibc = @import("../glibc.zig"); |
| 6236 | const link = @import("../link.zig"); | 6505 | const link = @import("../link.zig"); |
| 6237 | const lldMain = @import("../main.zig").lldMain; | 6506 | const lldMain = @import("../main.zig").lldMain; |
| 6507 | const merge_section = @import("Elf/merge_section.zig"); | ||
| 6238 | const musl = @import("../musl.zig"); | 6508 | const musl = @import("../musl.zig"); |
| 6239 | const relocatable = @import("Elf/relocatable.zig"); | 6509 | const relocatable = @import("Elf/relocatable.zig"); |
| 6240 | const relocation = @import("Elf/relocation.zig"); | 6510 | const relocation = @import("Elf/relocation.zig"); |
| ... | @@ -6260,10 +6530,13 @@ const GnuHashSection = synthetic_sections.GnuHashSection; | ... | @@ -6260,10 +6530,13 @@ const GnuHashSection = synthetic_sections.GnuHashSection; |
| 6260 | const GotSection = synthetic_sections.GotSection; | 6530 | const GotSection = synthetic_sections.GotSection; |
| 6261 | const GotPltSection = synthetic_sections.GotPltSection; | 6531 | const GotPltSection = synthetic_sections.GotPltSection; |
| 6262 | const HashSection = synthetic_sections.HashSection; | 6532 | const HashSection = synthetic_sections.HashSection; |
| 6533 | const InputMergeSection = merge_section.InputMergeSection; | ||
| 6263 | const LdScript = @import("Elf/LdScript.zig"); | 6534 | const LdScript = @import("Elf/LdScript.zig"); |
| 6264 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); | 6535 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); |
| 6265 | const Liveness = @import("../Liveness.zig"); | 6536 | const Liveness = @import("../Liveness.zig"); |
| 6266 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 6537 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 6538 | const MergeSection = merge_section.MergeSection; | ||
| 6539 | const MergeSubsection = merge_section.MergeSubsection; | ||
| 6267 | const Module = @import("../Module.zig"); | 6540 | const Module = @import("../Module.zig"); |
| 6268 | const Object = @import("Elf/Object.zig"); | 6541 | const Object = @import("Elf/Object.zig"); |
| 6269 | const InternPool = @import("../InternPool.zig"); | 6542 | const InternPool = @import("../InternPool.zig"); |
src/link/Elf/Atom.zig+187-114| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | /// Address allocated for this Atom. | 1 | /// Address allocated for this Atom. |
| 2 | value: u64 = 0, | 2 | value: i64 = 0, |
| 3 | 3 | ||
| 4 | /// Name of this Atom. | 4 | /// Name of this Atom. |
| 5 | name_offset: u32 = 0, | 5 | name_offset: u32 = 0, |
| ... | @@ -22,32 +22,19 @@ output_section_index: u32 = 0, | ... | @@ -22,32 +22,19 @@ output_section_index: u32 = 0, |
| 22 | /// Index of the input section containing this atom's relocs. | 22 | /// Index of the input section containing this atom's relocs. |
| 23 | relocs_section_index: u32 = 0, | 23 | relocs_section_index: u32 = 0, |
| 24 | 24 | ||
| 25 | /// Start index of the relocations belonging to this atom. | ||
| 26 | rel_index: u32 = 0, | ||
| 27 | |||
| 28 | /// Number of relocations belonging to this atom. | ||
| 29 | rel_num: u32 = 0, | ||
| 30 | |||
| 31 | /// Index of this atom in the linker's atoms table. | 25 | /// Index of this atom in the linker's atoms table. |
| 32 | atom_index: Index = 0, | 26 | atom_index: Index = 0, |
| 33 | 27 | ||
| 34 | /// Index of the thunk for this atom. | ||
| 35 | thunk_index: Thunk.Index = 0, | ||
| 36 | |||
| 37 | /// Flags we use for state tracking. | ||
| 38 | flags: Flags = .{}, | ||
| 39 | |||
| 40 | /// Start index of FDEs referencing this atom. | ||
| 41 | fde_start: u32 = 0, | ||
| 42 | |||
| 43 | /// End index of FDEs referencing this atom. | ||
| 44 | fde_end: u32 = 0, | ||
| 45 | |||
| 46 | /// Points to the previous and next neighbors, based on the `text_offset`. | 28 | /// Points to the previous and next neighbors, based on the `text_offset`. |
| 47 | /// This can be used to find, for example, the capacity of this `TextBlock`. | 29 | /// This can be used to find, for example, the capacity of this `TextBlock`. |
| 48 | prev_index: Index = 0, | 30 | prev_index: Index = 0, |
| 49 | next_index: Index = 0, | 31 | next_index: Index = 0, |
| 50 | 32 | ||
| 33 | /// Flags we use for state tracking. | ||
| 34 | flags: Flags = .{}, | ||
| 35 | |||
| 36 | extra_index: u32 = 0, | ||
| 37 | |||
| 51 | pub const Alignment = @import("../../InternPool.zig").Alignment; | 38 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
| 52 | 39 | ||
| 53 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { | 40 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| ... | @@ -57,10 +44,22 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 { | ... | @@ -57,10 +44,22 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 57 | }; | 44 | }; |
| 58 | } | 45 | } |
| 59 | 46 | ||
| 60 | pub fn address(self: Atom, elf_file: *Elf) u64 { | 47 | pub fn address(self: Atom, elf_file: *Elf) i64 { |
| 61 | const shndx = self.outputShndx() orelse return self.value; | 48 | const shndx = self.outputShndx() orelse return self.value; |
| 62 | const shdr = elf_file.shdrs.items[shndx]; | 49 | const shdr = elf_file.shdrs.items[shndx]; |
| 63 | return shdr.sh_addr + self.value; | 50 | return @as(i64, @intCast(shdr.sh_addr)) + self.value; |
| 51 | } | ||
| 52 | |||
| 53 | pub fn debugTombstoneValue(self: Atom, target: Symbol, elf_file: *Elf) ?u64 { | ||
| 54 | if (target.mergeSubsection(elf_file)) |msub| { | ||
| 55 | if (msub.alive) return null; | ||
| 56 | } | ||
| 57 | if (target.atom(elf_file)) |atom_ptr| { | ||
| 58 | if (atom_ptr.flags.alive) return null; | ||
| 59 | } | ||
| 60 | const atom_name = self.name(elf_file); | ||
| 61 | if (!mem.startsWith(u8, atom_name, ".debug")) return null; | ||
| 62 | return if (mem.eql(u8, atom_name, ".debug_loc") or mem.eql(u8, atom_name, ".debug_ranges")) 1 else 0; | ||
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | pub fn file(self: Atom, elf_file: *Elf) ?File { | 65 | pub fn file(self: Atom, elf_file: *Elf) ?File { |
| ... | @@ -68,7 +67,9 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { | ... | @@ -68,7 +67,9 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { |
| 68 | } | 67 | } |
| 69 | 68 | ||
| 70 | pub fn thunk(self: Atom, elf_file: *Elf) *Thunk { | 69 | pub fn thunk(self: Atom, elf_file: *Elf) *Thunk { |
| 71 | return elf_file.thunk(self.thunk_index); | 70 | assert(self.flags.thunk); |
| 71 | const extras = self.extra(elf_file).?; | ||
| 72 | return elf_file.thunk(extras.thunk); | ||
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { | 75 | pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { |
| ... | @@ -102,13 +103,13 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 { | ... | @@ -102,13 +103,13 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 { |
| 102 | next.address(elf_file) | 103 | next.address(elf_file) |
| 103 | else | 104 | else |
| 104 | std.math.maxInt(u32); | 105 | std.math.maxInt(u32); |
| 105 | return next_addr - self.address(elf_file); | 106 | return @intCast(next_addr - self.address(elf_file)); |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { | 109 | pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { |
| 109 | // No need to keep a free list node for the last block. | 110 | // No need to keep a free list node for the last block. |
| 110 | const next = elf_file.atom(self.next_index) orelse return false; | 111 | const next = elf_file.atom(self.next_index) orelse return false; |
| 111 | const cap = next.address(elf_file) - self.address(elf_file); | 112 | const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file)); |
| 112 | const ideal_cap = Elf.padToIdeal(self.size); | 113 | const ideal_cap = Elf.padToIdeal(self.size); |
| 113 | if (cap <= ideal_cap) return false; | 114 | if (cap <= ideal_cap) return false; |
| 114 | const surplus = cap - ideal_cap; | 115 | const surplus = cap - ideal_cap; |
| ... | @@ -141,8 +142,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -141,8 +142,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 141 | // Is it enough that we could fit this new atom? | 142 | // Is it enough that we could fit this new atom? |
| 142 | const cap = big_atom.capacity(elf_file); | 143 | const cap = big_atom.capacity(elf_file); |
| 143 | const ideal_capacity = Elf.padToIdeal(cap); | 144 | const ideal_capacity = Elf.padToIdeal(cap); |
| 144 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; | 145 | const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; |
| 145 | const capacity_end_vaddr = big_atom.value + cap; | 146 | const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; |
| 146 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | 147 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 147 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); | 148 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); |
| 148 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | 149 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| ... | @@ -167,14 +168,14 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -167,14 +168,14 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 167 | if (!keep_free_list_node) { | 168 | if (!keep_free_list_node) { |
| 168 | free_list_removal = i; | 169 | free_list_removal = i; |
| 169 | } | 170 | } |
| 170 | break :blk new_start_vaddr; | 171 | break :blk @intCast(new_start_vaddr); |
| 171 | } else if (elf_file.atom(last_atom_index.*)) |last| { | 172 | } else if (elf_file.atom(last_atom_index.*)) |last| { |
| 172 | const ideal_capacity = Elf.padToIdeal(last.size); | 173 | const ideal_capacity = Elf.padToIdeal(last.size); |
| 173 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; | 174 | const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity; |
| 174 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); | 175 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); |
| 175 | // Set up the metadata to be updated, after errors are no longer possible. | 176 | // Set up the metadata to be updated, after errors are no longer possible. |
| 176 | atom_placement = last.atom_index; | 177 | atom_placement = last.atom_index; |
| 177 | break :blk new_start_vaddr; | 178 | break :blk @intCast(new_start_vaddr); |
| 178 | } else { | 179 | } else { |
| 179 | break :blk 0; | 180 | break :blk 0; |
| 180 | } | 181 | } |
| ... | @@ -184,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -184,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 184 | self.atom_index, | 185 | self.atom_index, |
| 185 | self.name(elf_file), | 186 | self.name(elf_file), |
| 186 | self.address(elf_file), | 187 | self.address(elf_file), |
| 187 | self.address(elf_file) + self.size, | 188 | self.address(elf_file) + @as(i64, @intCast(self.size)), |
| 188 | }); | 189 | }); |
| 189 | 190 | ||
| 190 | const expand_section = if (atom_placement) |placement_index| | 191 | const expand_section = if (atom_placement) |placement_index| |
| ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 192 | else | 193 | else |
| 193 | true; | 194 | true; |
| 194 | if (expand_section) { | 195 | if (expand_section) { |
| 195 | const needed_size = self.value + self.size; | 196 | const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size))); |
| 196 | try elf_file.growAllocSection(self.outputShndx().?, needed_size); | 197 | try elf_file.growAllocSection(self.outputShndx().?, needed_size); |
| 197 | last_atom_index.* = self.atom_index; | 198 | last_atom_index.* = self.atom_index; |
| 198 | 199 | ||
| ... | @@ -242,7 +243,7 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { | ... | @@ -242,7 +243,7 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 244 | pub fn grow(self: *Atom, elf_file: *Elf) !void { | 245 | pub fn grow(self: *Atom, elf_file: *Elf) !void { |
| 245 | if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file)) | 246 | if (!self.alignment.check(@intCast(self.value)) or self.size > self.capacity(elf_file)) |
| 246 | try self.allocate(elf_file); | 247 | try self.allocate(elf_file); |
| 247 | } | 248 | } |
| 248 | 249 | ||
| ... | @@ -309,11 +310,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void { | ... | @@ -309,11 +310,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void { |
| 309 | 310 | ||
| 310 | pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela { | 311 | pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela { |
| 311 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; | 312 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; |
| 312 | return switch (self.file(elf_file).?) { | 313 | switch (self.file(elf_file).?) { |
| 313 | .zig_object => |x| x.relocs.items[shndx].items, | 314 | .zig_object => |x| return x.relocs.items[shndx].items, |
| 314 | .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num], | 315 | .object => |x| { |
| 316 | const extras = self.extra(elf_file).?; | ||
| 317 | return x.relocs.items[extras.rel_index..][0..extras.rel_count]; | ||
| 318 | }, | ||
| 315 | else => unreachable, | 319 | else => unreachable, |
| 316 | }; | 320 | } |
| 317 | } | 321 | } |
| 318 | 322 | ||
| 319 | pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void { | 323 | pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void { |
| ... | @@ -329,11 +333,14 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El | ... | @@ -329,11 +333,14 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El |
| 329 | }; | 333 | }; |
| 330 | const target = elf_file.symbol(target_index); | 334 | const target = elf_file.symbol(target_index); |
| 331 | const r_type = rel.r_type(); | 335 | const r_type = rel.r_type(); |
| 332 | const r_offset = self.value + rel.r_offset; | 336 | const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset))); |
| 333 | var r_addend = rel.r_addend; | 337 | var r_addend = rel.r_addend; |
| 334 | var r_sym: u32 = 0; | 338 | var r_sym: u32 = 0; |
| 335 | switch (target.type(elf_file)) { | 339 | switch (target.type(elf_file)) { |
| 336 | elf.STT_SECTION => { | 340 | elf.STT_SECTION => if (target.mergeSubsection(elf_file)) |msub| { |
| 341 | r_addend += @intCast(target.address(.{}, elf_file)); | ||
| 342 | r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index); | ||
| 343 | } else { | ||
| 337 | r_addend += @intCast(target.address(.{}, elf_file)); | 344 | r_addend += @intCast(target.address(.{}, elf_file)); |
| 338 | r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?); | 345 | r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?); |
| 339 | }, | 346 | }, |
| ... | @@ -359,9 +366,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El | ... | @@ -359,9 +366,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El |
| 359 | } | 366 | } |
| 360 | 367 | ||
| 361 | pub fn fdes(self: Atom, elf_file: *Elf) []Fde { | 368 | pub fn fdes(self: Atom, elf_file: *Elf) []Fde { |
| 362 | if (self.fde_start == self.fde_end) return &[0]Fde{}; | 369 | if (!self.flags.fde) return &[0]Fde{}; |
| 370 | const extras = self.extra(elf_file).?; | ||
| 363 | const object = self.file(elf_file).?.object; | 371 | const object = self.file(elf_file).?.object; |
| 364 | return object.fdes.items[self.fde_start..self.fde_end]; | 372 | return object.fdes.items[extras.fde_start..][0..extras.fde_count]; |
| 365 | } | 373 | } |
| 366 | 374 | ||
| 367 | pub fn markFdesDead(self: Atom, elf_file: *Elf) void { | 375 | pub fn markFdesDead(self: Atom, elf_file: *Elf) void { |
| ... | @@ -419,6 +427,12 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -419,6 +427,12 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 419 | }; | 427 | }; |
| 420 | const symbol = elf_file.symbol(symbol_index); | 428 | const symbol = elf_file.symbol(symbol_index); |
| 421 | 429 | ||
| 430 | const is_synthetic_symbol = switch (file_ptr) { | ||
| 431 | .zig_object => false, // TODO: implement this once we support merge sections in ZigObject | ||
| 432 | .object => |x| rel.r_sym() >= x.symtab.items.len, | ||
| 433 | else => unreachable, | ||
| 434 | }; | ||
| 435 | |||
| 422 | // Check for violation of One Definition Rule for COMDATs. | 436 | // Check for violation of One Definition Rule for COMDATs. |
| 423 | if (symbol.file(elf_file) == null) { | 437 | if (symbol.file(elf_file) == null) { |
| 424 | // TODO convert into an error | 438 | // TODO convert into an error |
| ... | @@ -431,7 +445,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -431,7 +445,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 431 | } | 445 | } |
| 432 | 446 | ||
| 433 | // Report an undefined symbol. | 447 | // Report an undefined symbol. |
| 434 | if (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)) continue; | 448 | if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs))) |
| 449 | continue; | ||
| 435 | 450 | ||
| 436 | if (symbol.isIFunc(elf_file)) { | 451 | if (symbol.isIFunc(elf_file)) { |
| 437 | symbol.flags.needs_got = true; | 452 | symbol.flags.needs_got = true; |
| ... | @@ -743,21 +758,21 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi | ... | @@ -743,21 +758,21 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 743 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | 758 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ |
| 744 | // | 759 | // |
| 745 | // Address of the source atom. | 760 | // Address of the source atom. |
| 746 | const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset)); | 761 | const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset)); |
| 747 | // Addend from the relocation. | 762 | // Addend from the relocation. |
| 748 | const A = rel.r_addend; | 763 | const A = rel.r_addend; |
| 749 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | 764 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. |
| 750 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | 765 | const S = target.address(.{}, elf_file); |
| 751 | // Address of the global offset table. | 766 | // Address of the global offset table. |
| 752 | const GOT = @as(i64, @intCast(elf_file.gotAddress())); | 767 | const GOT = elf_file.gotAddress(); |
| 753 | // Address of the .zig.got table entry if any. | 768 | // Address of the .zig.got table entry if any. |
| 754 | const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file))); | 769 | const ZIG_GOT = target.zigGotAddress(elf_file); |
| 755 | // Relative offset to the start of the global offset table. | 770 | // Relative offset to the start of the global offset table. |
| 756 | const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT; | 771 | const G = target.gotAddress(elf_file) - GOT; |
| 757 | // // Address of the thread pointer. | 772 | // // Address of the thread pointer. |
| 758 | const TP = @as(i64, @intCast(elf_file.tpAddress())); | 773 | const TP = elf_file.tpAddress(); |
| 759 | // Address of the dynamic thread pointer. | 774 | // Address of the dynamic thread pointer. |
| 760 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | 775 | const DTP = elf_file.dtpAddress(); |
| 761 | 776 | ||
| 762 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ | 777 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ |
| 763 | relocation.fmtRelocType(rel.r_type(), cpu_arch), | 778 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| ... | @@ -814,9 +829,9 @@ fn resolveDynAbsReloc( | ... | @@ -814,9 +829,9 @@ fn resolveDynAbsReloc( |
| 814 | const comp = elf_file.base.comp; | 829 | const comp = elf_file.base.comp; |
| 815 | const gpa = comp.gpa; | 830 | const gpa = comp.gpa; |
| 816 | const cpu_arch = elf_file.getTarget().cpu.arch; | 831 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 817 | const P = self.address(elf_file) + rel.r_offset; | 832 | const P: u64 = @intCast(self.address(elf_file) + @as(i64, @intCast(rel.r_offset))); |
| 818 | const A = rel.r_addend; | 833 | const A = rel.r_addend; |
| 819 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | 834 | const S = target.address(.{}, elf_file); |
| 820 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; | 835 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; |
| 821 | 836 | ||
| 822 | const num_dynrelocs = switch (self.file(elf_file).?) { | 837 | const num_dynrelocs = switch (self.file(elf_file).?) { |
| ... | @@ -884,7 +899,7 @@ fn resolveDynAbsReloc( | ... | @@ -884,7 +899,7 @@ fn resolveDynAbsReloc( |
| 884 | }, | 899 | }, |
| 885 | 900 | ||
| 886 | .ifunc => { | 901 | .ifunc => { |
| 887 | const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file))); | 902 | const S_ = target.address(.{ .plt = false }, elf_file); |
| 888 | elf_file.addRelaDynAssumeCapacity(.{ | 903 | elf_file.addRelaDynAssumeCapacity(.{ |
| 889 | .offset = P, | 904 | .offset = P, |
| 890 | .type = relocation.encode(.irel, cpu_arch), | 905 | .type = relocation.encode(.irel, cpu_arch), |
| ... | @@ -924,6 +939,11 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any | ... | @@ -924,6 +939,11 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 924 | else => unreachable, | 939 | else => unreachable, |
| 925 | }; | 940 | }; |
| 926 | const target = elf_file.symbol(target_index); | 941 | const target = elf_file.symbol(target_index); |
| 942 | const is_synthetic_symbol = switch (file_ptr) { | ||
| 943 | .zig_object => false, // TODO: implement this once we support merge sections in ZigObject | ||
| 944 | .object => |x| rel.r_sym() >= x.symtab.items.len, | ||
| 945 | else => unreachable, | ||
| 946 | }; | ||
| 927 | 947 | ||
| 928 | // Check for violation of One Definition Rule for COMDATs. | 948 | // Check for violation of One Definition Rule for COMDATs. |
| 929 | if (target.file(elf_file) == null) { | 949 | if (target.file(elf_file) == null) { |
| ... | @@ -937,20 +957,21 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any | ... | @@ -937,20 +957,21 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 937 | } | 957 | } |
| 938 | 958 | ||
| 939 | // Report an undefined symbol. | 959 | // Report an undefined symbol. |
| 940 | if (try self.reportUndefined(elf_file, target, target_index, rel, undefs)) continue; | 960 | if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs))) |
| 961 | continue; | ||
| 941 | 962 | ||
| 942 | // We will use equation format to resolve relocations: | 963 | // We will use equation format to resolve relocations: |
| 943 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | 964 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ |
| 944 | // | 965 | // |
| 945 | const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset)); | 966 | const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset)); |
| 946 | // Addend from the relocation. | 967 | // Addend from the relocation. |
| 947 | const A = rel.r_addend; | 968 | const A = rel.r_addend; |
| 948 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | 969 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. |
| 949 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | 970 | const S = target.address(.{}, elf_file); |
| 950 | // Address of the global offset table. | 971 | // Address of the global offset table. |
| 951 | const GOT = @as(i64, @intCast(elf_file.gotAddress())); | 972 | const GOT = elf_file.gotAddress(); |
| 952 | // Address of the dynamic thread pointer. | 973 | // Address of the dynamic thread pointer. |
| 953 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | 974 | const DTP = elf_file.dtpAddress(); |
| 954 | 975 | ||
| 955 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 }; | 976 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 }; |
| 956 | 977 | ||
| ... | @@ -984,6 +1005,35 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any | ... | @@ -984,6 +1005,35 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 984 | if (has_reloc_errors) return error.RelocFailure; | 1005 | if (has_reloc_errors) return error.RelocFailure; |
| 985 | } | 1006 | } |
| 986 | 1007 | ||
| 1008 | const AddExtraOpts = struct { | ||
| 1009 | thunk: ?u32 = null, | ||
| 1010 | fde_start: ?u32 = null, | ||
| 1011 | fde_count: ?u32 = null, | ||
| 1012 | rel_index: ?u32 = null, | ||
| 1013 | rel_count: ?u32 = null, | ||
| 1014 | }; | ||
| 1015 | |||
| 1016 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void { | ||
| 1017 | if (atom.extra(elf_file) == null) { | ||
| 1018 | atom.extra_index = try elf_file.addAtomExtra(.{}); | ||
| 1019 | } | ||
| 1020 | var extras = atom.extra(elf_file).?; | ||
| 1021 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { | ||
| 1022 | if (@field(opts, field.name)) |x| { | ||
| 1023 | @field(extras, field.name) = x; | ||
| 1024 | } | ||
| 1025 | } | ||
| 1026 | atom.setExtra(extras, elf_file); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra { | ||
| 1030 | return elf_file.atomExtra(atom.extra_index); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void { | ||
| 1034 | elf_file.setAtomExtra(atom.extra_index, extras); | ||
| 1035 | } | ||
| 1036 | |||
| 987 | pub fn format( | 1037 | pub fn format( |
| 988 | atom: Atom, | 1038 | atom: Atom, |
| 989 | comptime unused_fmt_string: []const u8, | 1039 | comptime unused_fmt_string: []const u8, |
| ... | @@ -1023,12 +1073,13 @@ fn format2( | ... | @@ -1023,12 +1073,13 @@ fn format2( |
| 1023 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), | 1073 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), |
| 1024 | atom.output_section_index, atom.alignment, atom.size, | 1074 | atom.output_section_index, atom.alignment, atom.size, |
| 1025 | }); | 1075 | }); |
| 1026 | if (atom.fde_start != atom.fde_end) { | 1076 | if (atom.flags.fde) { |
| 1027 | try writer.writeAll(" : fdes{ "); | 1077 | try writer.writeAll(" : fdes{ "); |
| 1028 | for (atom.fdes(elf_file), atom.fde_start..) |fde, i| { | 1078 | const extras = atom.extra(elf_file).?; |
| 1079 | for (atom.fdes(elf_file), extras.fde_start..) |fde, i| { | ||
| 1029 | try writer.print("{d}", .{i}); | 1080 | try writer.print("{d}", .{i}); |
| 1030 | if (!fde.alive) try writer.writeAll("([*])"); | 1081 | if (!fde.alive) try writer.writeAll("([*])"); |
| 1031 | if (i < atom.fde_end - 1) try writer.writeAll(", "); | 1082 | if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", "); |
| 1032 | } | 1083 | } |
| 1033 | try writer.writeAll(" }"); | 1084 | try writer.writeAll(" }"); |
| 1034 | } | 1085 | } |
| ... | @@ -1045,6 +1096,12 @@ pub const Flags = packed struct { | ... | @@ -1045,6 +1096,12 @@ pub const Flags = packed struct { |
| 1045 | 1096 | ||
| 1046 | /// Specifies if the atom has been visited during garbage collection. | 1097 | /// Specifies if the atom has been visited during garbage collection. |
| 1047 | visited: bool = false, | 1098 | visited: bool = false, |
| 1099 | |||
| 1100 | /// Whether this atom has a range extension thunk. | ||
| 1101 | thunk: bool = false, | ||
| 1102 | |||
| 1103 | /// Whether this atom has FDE records. | ||
| 1104 | fde: bool = false, | ||
| 1048 | }; | 1105 | }; |
| 1049 | 1106 | ||
| 1050 | const x86_64 = struct { | 1107 | const x86_64 = struct { |
| ... | @@ -1235,10 +1292,10 @@ const x86_64 = struct { | ... | @@ -1235,10 +1292,10 @@ const x86_64 = struct { |
| 1235 | 1292 | ||
| 1236 | .TLSGD => { | 1293 | .TLSGD => { |
| 1237 | if (target.flags.has_tlsgd) { | 1294 | if (target.flags.has_tlsgd) { |
| 1238 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); | 1295 | const S_ = target.tlsGdAddress(elf_file); |
| 1239 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | 1296 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1240 | } else if (target.flags.has_gottp) { | 1297 | } else if (target.flags.has_gottp) { |
| 1241 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | 1298 | const S_ = target.gotTpAddress(elf_file); |
| 1242 | try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream); | 1299 | try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream); |
| 1243 | } else { | 1300 | } else { |
| 1244 | try x86_64.relaxTlsGdToLe( | 1301 | try x86_64.relaxTlsGdToLe( |
| ... | @@ -1254,13 +1311,13 @@ const x86_64 = struct { | ... | @@ -1254,13 +1311,13 @@ const x86_64 = struct { |
| 1254 | .TLSLD => { | 1311 | .TLSLD => { |
| 1255 | if (elf_file.got.tlsld_index) |entry_index| { | 1312 | if (elf_file.got.tlsld_index) |entry_index| { |
| 1256 | const tlsld_entry = elf_file.got.entries.items[entry_index]; | 1313 | const tlsld_entry = elf_file.got.entries.items[entry_index]; |
| 1257 | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); | 1314 | const S_ = tlsld_entry.address(elf_file); |
| 1258 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | 1315 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1259 | } else { | 1316 | } else { |
| 1260 | try x86_64.relaxTlsLdToLe( | 1317 | try x86_64.relaxTlsLdToLe( |
| 1261 | atom, | 1318 | atom, |
| 1262 | &.{ rel, it.next().? }, | 1319 | &.{ rel, it.next().? }, |
| 1263 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), | 1320 | @as(i32, @intCast(TP - elf_file.tlsAddress())), |
| 1264 | elf_file, | 1321 | elf_file, |
| 1265 | stream, | 1322 | stream, |
| 1266 | ); | 1323 | ); |
| ... | @@ -1269,7 +1326,7 @@ const x86_64 = struct { | ... | @@ -1269,7 +1326,7 @@ const x86_64 = struct { |
| 1269 | 1326 | ||
| 1270 | .GOTPC32_TLSDESC => { | 1327 | .GOTPC32_TLSDESC => { |
| 1271 | if (target.flags.has_tlsdesc) { | 1328 | if (target.flags.has_tlsdesc) { |
| 1272 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); | 1329 | const S_ = target.tlsDescAddress(elf_file); |
| 1273 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | 1330 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1274 | } else { | 1331 | } else { |
| 1275 | x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch { | 1332 | x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch { |
| ... | @@ -1293,7 +1350,7 @@ const x86_64 = struct { | ... | @@ -1293,7 +1350,7 @@ const x86_64 = struct { |
| 1293 | 1350 | ||
| 1294 | .GOTTPOFF => { | 1351 | .GOTTPOFF => { |
| 1295 | if (target.flags.has_gottp) { | 1352 | if (target.flags.has_gottp) { |
| 1296 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | 1353 | const S_ = target.gotTpAddress(elf_file); |
| 1297 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | 1354 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1298 | } else { | 1355 | } else { |
| 1299 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]); | 1356 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]); |
| ... | @@ -1336,9 +1393,18 @@ const x86_64 = struct { | ... | @@ -1336,9 +1393,18 @@ const x86_64 = struct { |
| 1336 | .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), | 1393 | .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), |
| 1337 | .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), | 1394 | .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), |
| 1338 | .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), | 1395 | .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), |
| 1339 | .@"64" => try cwriter.writeInt(i64, S + A, .little), | 1396 | .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value| |
| 1340 | .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), | 1397 | try cwriter.writeInt(u64, value, .little) |
| 1341 | .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | 1398 | else |
| 1399 | try cwriter.writeInt(i64, S + A, .little), | ||
| 1400 | .DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| | ||
| 1401 | try cwriter.writeInt(u64, value, .little) | ||
| 1402 | else | ||
| 1403 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), | ||
| 1404 | .DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| | ||
| 1405 | try cwriter.writeInt(u64, value, .little) | ||
| 1406 | else | ||
| 1407 | try cwriter.writeInt(i64, S + A - DTP, .little), | ||
| 1342 | .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), | 1408 | .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), |
| 1343 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), | 1409 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), |
| 1344 | .SIZE32 => { | 1410 | .SIZE32 => { |
| ... | @@ -1720,7 +1786,7 @@ const aarch64 = struct { | ... | @@ -1720,7 +1786,7 @@ const aarch64 = struct { |
| 1720 | .object => |x| x.symbols.items[rel.r_sym()], | 1786 | .object => |x| x.symbols.items[rel.r_sym()], |
| 1721 | else => unreachable, | 1787 | else => unreachable, |
| 1722 | }; | 1788 | }; |
| 1723 | const S_: i64 = @intCast(th.targetAddress(target_index, elf_file)); | 1789 | const S_ = th.targetAddress(target_index, elf_file); |
| 1724 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; | 1790 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 1725 | }; | 1791 | }; |
| 1726 | aarch64_util.writeBranchImm(disp, code); | 1792 | aarch64_util.writeBranchImm(disp, code); |
| ... | @@ -1738,16 +1804,12 @@ const aarch64 = struct { | ... | @@ -1738,16 +1804,12 @@ const aarch64 = struct { |
| 1738 | 1804 | ||
| 1739 | .ADR_PREL_PG_HI21 => { | 1805 | .ADR_PREL_PG_HI21 => { |
| 1740 | // TODO: check for relaxation of ADRP+ADD | 1806 | // TODO: check for relaxation of ADRP+ADD |
| 1741 | const saddr = @as(u64, @intCast(P)); | 1807 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A))); |
| 1742 | const taddr = @as(u64, @intCast(S + A)); | ||
| 1743 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); | ||
| 1744 | aarch64_util.writeAdrpInst(pages, code); | 1808 | aarch64_util.writeAdrpInst(pages, code); |
| 1745 | }, | 1809 | }, |
| 1746 | 1810 | ||
| 1747 | .ADR_GOT_PAGE => if (target.flags.has_got) { | 1811 | .ADR_GOT_PAGE => if (target.flags.has_got) { |
| 1748 | const saddr = @as(u64, @intCast(P)); | 1812 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A))); |
| 1749 | const taddr = @as(u64, @intCast(G + GOT + A)); | ||
| 1750 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); | ||
| 1751 | aarch64_util.writeAdrpInst(pages, code); | 1813 | aarch64_util.writeAdrpInst(pages, code); |
| 1752 | } else { | 1814 | } else { |
| 1753 | // TODO: relax | 1815 | // TODO: relax |
| ... | @@ -1802,46 +1864,38 @@ const aarch64 = struct { | ... | @@ -1802,46 +1864,38 @@ const aarch64 = struct { |
| 1802 | }, | 1864 | }, |
| 1803 | 1865 | ||
| 1804 | .TLSIE_ADR_GOTTPREL_PAGE21 => { | 1866 | .TLSIE_ADR_GOTTPREL_PAGE21 => { |
| 1805 | const S_: i64 = @intCast(target.gotTpAddress(elf_file)); | 1867 | const S_ = target.gotTpAddress(elf_file); |
| 1806 | const saddr: u64 = @intCast(P); | 1868 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1807 | const taddr: u64 = @intCast(S_ + A); | 1869 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); |
| 1808 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | ||
| 1809 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | ||
| 1810 | aarch64_util.writeAdrpInst(pages, code); | 1870 | aarch64_util.writeAdrpInst(pages, code); |
| 1811 | }, | 1871 | }, |
| 1812 | 1872 | ||
| 1813 | .TLSIE_LD64_GOTTPREL_LO12_NC => { | 1873 | .TLSIE_LD64_GOTTPREL_LO12_NC => { |
| 1814 | const S_: i64 = @intCast(target.gotTpAddress(elf_file)); | 1874 | const S_ = target.gotTpAddress(elf_file); |
| 1815 | const taddr: u64 = @intCast(S_ + A); | 1875 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1816 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | 1876 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1817 | const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); | ||
| 1818 | aarch64_util.writeLoadStoreRegInst(offset, code); | 1877 | aarch64_util.writeLoadStoreRegInst(offset, code); |
| 1819 | }, | 1878 | }, |
| 1820 | 1879 | ||
| 1821 | .TLSGD_ADR_PAGE21 => { | 1880 | .TLSGD_ADR_PAGE21 => { |
| 1822 | const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); | 1881 | const S_ = target.tlsGdAddress(elf_file); |
| 1823 | const saddr: u64 = @intCast(P); | 1882 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1824 | const taddr: u64 = @intCast(S_ + A); | 1883 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); |
| 1825 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | ||
| 1826 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | ||
| 1827 | aarch64_util.writeAdrpInst(pages, code); | 1884 | aarch64_util.writeAdrpInst(pages, code); |
| 1828 | }, | 1885 | }, |
| 1829 | 1886 | ||
| 1830 | .TLSGD_ADD_LO12_NC => { | 1887 | .TLSGD_ADD_LO12_NC => { |
| 1831 | const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); | 1888 | const S_ = target.tlsGdAddress(elf_file); |
| 1832 | const taddr: u64 = @intCast(S_ + A); | 1889 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1833 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | 1890 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1834 | const offset: u12 = @truncate(taddr); | ||
| 1835 | aarch64_util.writeAddImmInst(offset, code); | 1891 | aarch64_util.writeAddImmInst(offset, code); |
| 1836 | }, | 1892 | }, |
| 1837 | 1893 | ||
| 1838 | .TLSDESC_ADR_PAGE21 => { | 1894 | .TLSDESC_ADR_PAGE21 => { |
| 1839 | if (target.flags.has_tlsdesc) { | 1895 | if (target.flags.has_tlsdesc) { |
| 1840 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | 1896 | const S_ = target.tlsDescAddress(elf_file); |
| 1841 | const saddr: u64 = @intCast(P); | 1897 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1842 | const taddr: u64 = @intCast(S_ + A); | 1898 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); |
| 1843 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | ||
| 1844 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | ||
| 1845 | aarch64_util.writeAdrpInst(pages, code); | 1899 | aarch64_util.writeAdrpInst(pages, code); |
| 1846 | } else { | 1900 | } else { |
| 1847 | relocs_log.debug(" relaxing adrp => nop", .{}); | 1901 | relocs_log.debug(" relaxing adrp => nop", .{}); |
| ... | @@ -1851,10 +1905,9 @@ const aarch64 = struct { | ... | @@ -1851,10 +1905,9 @@ const aarch64 = struct { |
| 1851 | 1905 | ||
| 1852 | .TLSDESC_LD64_LO12 => { | 1906 | .TLSDESC_LD64_LO12 => { |
| 1853 | if (target.flags.has_tlsdesc) { | 1907 | if (target.flags.has_tlsdesc) { |
| 1854 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | 1908 | const S_ = target.tlsDescAddress(elf_file); |
| 1855 | const taddr: u64 = @intCast(S_ + A); | 1909 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1856 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | 1910 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1857 | const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); | ||
| 1858 | aarch64_util.writeLoadStoreRegInst(offset, code); | 1911 | aarch64_util.writeLoadStoreRegInst(offset, code); |
| 1859 | } else { | 1912 | } else { |
| 1860 | relocs_log.debug(" relaxing ldr => nop", .{}); | 1913 | relocs_log.debug(" relaxing ldr => nop", .{}); |
| ... | @@ -1864,10 +1917,9 @@ const aarch64 = struct { | ... | @@ -1864,10 +1917,9 @@ const aarch64 = struct { |
| 1864 | 1917 | ||
| 1865 | .TLSDESC_ADD_LO12 => { | 1918 | .TLSDESC_ADD_LO12 => { |
| 1866 | if (target.flags.has_tlsdesc) { | 1919 | if (target.flags.has_tlsdesc) { |
| 1867 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | 1920 | const S_ = target.tlsDescAddress(elf_file); |
| 1868 | const taddr: u64 = @intCast(S_ + A); | 1921 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1869 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | 1922 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1870 | const offset: u12 = @truncate(taddr); | ||
| 1871 | aarch64_util.writeAddImmInst(offset, code); | 1923 | aarch64_util.writeAddImmInst(offset, code); |
| 1872 | } else { | 1924 | } else { |
| 1873 | const old_inst = Instruction{ | 1925 | const old_inst = Instruction{ |
| ... | @@ -1912,7 +1964,6 @@ const aarch64 = struct { | ... | @@ -1912,7 +1964,6 @@ const aarch64 = struct { |
| 1912 | ) !void { | 1964 | ) !void { |
| 1913 | _ = it; | 1965 | _ = it; |
| 1914 | _ = code; | 1966 | _ = code; |
| 1915 | _ = target; | ||
| 1916 | 1967 | ||
| 1917 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); | 1968 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); |
| 1918 | const cwriter = stream.writer(); | 1969 | const cwriter = stream.writer(); |
| ... | @@ -1922,7 +1973,10 @@ const aarch64 = struct { | ... | @@ -1922,7 +1973,10 @@ const aarch64 = struct { |
| 1922 | switch (r_type) { | 1973 | switch (r_type) { |
| 1923 | .NONE => unreachable, | 1974 | .NONE => unreachable, |
| 1924 | .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), | 1975 | .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), |
| 1925 | .ABS64 => try cwriter.writeInt(i64, S + A, .little), | 1976 | .ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| |
| 1977 | try cwriter.writeInt(u64, value, .little) | ||
| 1978 | else | ||
| 1979 | try cwriter.writeInt(i64, S + A, .little), | ||
| 1926 | else => try atom.reportUnhandledRelocError(rel, elf_file), | 1980 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 1927 | } | 1981 | } |
| 1928 | } | 1982 | } |
| ... | @@ -2047,7 +2101,7 @@ const riscv = struct { | ... | @@ -2047,7 +2101,7 @@ const riscv = struct { |
| 2047 | const atom_addr = atom.address(elf_file); | 2101 | const atom_addr = atom.address(elf_file); |
| 2048 | const pos = it.pos; | 2102 | const pos = it.pos; |
| 2049 | const pair = while (it.prev()) |pair| { | 2103 | const pair = while (it.prev()) |pair| { |
| 2050 | if (S == atom_addr + pair.r_offset) break pair; | 2104 | if (S == atom_addr + @as(i64, @intCast(pair.r_offset))) break pair; |
| 2051 | } else { | 2105 | } else { |
| 2052 | // TODO: implement searching forward | 2106 | // TODO: implement searching forward |
| 2053 | var err = try elf_file.addErrorWithNotes(1); | 2107 | var err = try elf_file.addErrorWithNotes(1); |
| ... | @@ -2065,10 +2119,10 @@ const riscv = struct { | ... | @@ -2065,10 +2119,10 @@ const riscv = struct { |
| 2065 | .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]), | 2119 | .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]), |
| 2066 | else => unreachable, | 2120 | else => unreachable, |
| 2067 | }; | 2121 | }; |
| 2068 | const S_ = @as(i64, @intCast(target_.address(.{}, elf_file))); | 2122 | const S_ = target_.address(.{}, elf_file); |
| 2069 | const A_ = pair.r_addend; | 2123 | const A_ = pair.r_addend; |
| 2070 | const P_ = @as(i64, @intCast(atom_addr + pair.r_offset)); | 2124 | const P_ = atom_addr + @as(i64, @intCast(pair.r_offset)); |
| 2071 | const G_ = @as(i64, @intCast(target_.gotAddress(elf_file))) - GOT; | 2125 | const G_ = target_.gotAddress(elf_file) - GOT; |
| 2072 | const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) { | 2126 | const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) { |
| 2073 | .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow, | 2127 | .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow, |
| 2074 | .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow, | 2128 | .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow, |
| ... | @@ -2096,7 +2150,6 @@ const riscv = struct { | ... | @@ -2096,7 +2150,6 @@ const riscv = struct { |
| 2096 | code: []u8, | 2150 | code: []u8, |
| 2097 | stream: anytype, | 2151 | stream: anytype, |
| 2098 | ) !void { | 2152 | ) !void { |
| 2099 | _ = target; | ||
| 2100 | _ = it; | 2153 | _ = it; |
| 2101 | 2154 | ||
| 2102 | const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); | 2155 | const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); |
| ... | @@ -2111,7 +2164,10 @@ const riscv = struct { | ... | @@ -2111,7 +2164,10 @@ const riscv = struct { |
| 2111 | .NONE => unreachable, | 2164 | .NONE => unreachable, |
| 2112 | 2165 | ||
| 2113 | .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), | 2166 | .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), |
| 2114 | .@"64" => try cwriter.writeInt(i64, S + A, .little), | 2167 | .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value| |
| 2168 | try cwriter.writeInt(u64, value, .little) | ||
| 2169 | else | ||
| 2170 | try cwriter.writeInt(i64, S + A, .little), | ||
| 2115 | 2171 | ||
| 2116 | .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A), | 2172 | .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A), |
| 2117 | .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A), | 2173 | .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A), |
| ... | @@ -2170,6 +2226,23 @@ const RelocsIterator = struct { | ... | @@ -2170,6 +2226,23 @@ const RelocsIterator = struct { |
| 2170 | } | 2226 | } |
| 2171 | }; | 2227 | }; |
| 2172 | 2228 | ||
| 2229 | pub const Extra = struct { | ||
| 2230 | /// Index of the range extension thunk of this atom. | ||
| 2231 | thunk: u32 = 0, | ||
| 2232 | |||
| 2233 | /// Start index of FDEs referencing this atom. | ||
| 2234 | fde_start: u32 = 0, | ||
| 2235 | |||
| 2236 | /// Count of FDEs referencing this atom. | ||
| 2237 | fde_count: u32 = 0, | ||
| 2238 | |||
| 2239 | /// Start index of relocations belonging to this atom. | ||
| 2240 | rel_index: u32 = 0, | ||
| 2241 | |||
| 2242 | /// Count of relocations belonging to this atom. | ||
| 2243 | rel_count: u32 = 0, | ||
| 2244 | }; | ||
| 2245 | |||
| 2173 | const std = @import("std"); | 2246 | const std = @import("std"); |
| 2174 | const assert = std.debug.assert; | 2247 | const assert = std.debug.assert; |
| 2175 | const elf = std.elf; | 2248 | const elf = std.elf; |
src/link/Elf/LinkerDefined.zig+2-2| ... | @@ -60,10 +60,10 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void { | ... | @@ -60,10 +60,10 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void { |
| 60 | if (file_ptr.index() != self.index) continue; | 60 | if (file_ptr.index() != self.index) continue; |
| 61 | global.flags.output_symtab = true; | 61 | global.flags.output_symtab = true; |
| 62 | if (global.isLocal(elf_file)) { | 62 | if (global.isLocal(elf_file)) { |
| 63 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file); | 63 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); |
| 64 | self.output_symtab_ctx.nlocals += 1; | 64 | self.output_symtab_ctx.nlocals += 1; |
| 65 | } else { | 65 | } else { |
| 66 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file); | 66 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); |
| 67 | self.output_symtab_ctx.nglobals += 1; | 67 | self.output_symtab_ctx.nglobals += 1; |
| 68 | } | 68 | } |
| 69 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; | 69 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; |
src/link/Elf/Object.zig+230-19| ... | @@ -15,6 +15,8 @@ comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, | ... | @@ -15,6 +15,8 @@ comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, |
| 15 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, | 15 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, |
| 16 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | 16 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 17 | 17 | ||
| 18 | merge_sections: std.ArrayListUnmanaged(InputMergeSection.Index) = .{}, | ||
| 19 | |||
| 18 | fdes: std.ArrayListUnmanaged(Fde) = .{}, | 20 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 19 | cies: std.ArrayListUnmanaged(Cie) = .{}, | 21 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 20 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | 22 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, |
| ... | @@ -51,6 +53,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -51,6 +53,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 51 | self.fdes.deinit(allocator); | 53 | self.fdes.deinit(allocator); |
| 52 | self.cies.deinit(allocator); | 54 | self.cies.deinit(allocator); |
| 53 | self.eh_frame_data.deinit(allocator); | 55 | self.eh_frame_data.deinit(allocator); |
| 56 | self.merge_sections.deinit(allocator); | ||
| 54 | } | 57 | } |
| 55 | 58 | ||
| 56 | pub fn parse(self: *Object, elf_file: *Elf) !void { | 59 | pub fn parse(self: *Object, elf_file: *Elf) !void { |
| ... | @@ -242,11 +245,12 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: | ... | @@ -242,11 +245,12 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 242 | const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); | 245 | const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); |
| 243 | defer allocator.free(relocs); | 246 | defer allocator.free(relocs); |
| 244 | atom.relocs_section_index = @intCast(i); | 247 | atom.relocs_section_index = @intCast(i); |
| 245 | atom.rel_index = @intCast(self.relocs.items.len); | 248 | const rel_index: u32 = @intCast(self.relocs.items.len); |
| 246 | atom.rel_num = @intCast(relocs.len); | 249 | const rel_count: u32 = @intCast(relocs.len); |
| 250 | try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file); | ||
| 247 | try self.relocs.appendUnalignedSlice(allocator, relocs); | 251 | try self.relocs.appendUnalignedSlice(allocator, relocs); |
| 248 | if (elf_file.getTarget().cpu.arch == .riscv64) { | 252 | if (elf_file.getTarget().cpu.arch == .riscv64) { |
| 249 | sortRelocs(self.relocs.items[atom.rel_index..][0..atom.rel_num]); | 253 | sortRelocs(self.relocs.items[rel_index..][0..rel_count]); |
| 250 | } | 254 | } |
| 251 | } | 255 | } |
| 252 | }, | 256 | }, |
| ... | @@ -279,8 +283,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O | ... | @@ -279,8 +283,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O |
| 279 | const name = blk: { | 283 | const name = blk: { |
| 280 | const name = self.getString(shdr.sh_name); | 284 | const name = self.getString(shdr.sh_name); |
| 281 | if (elf_file.base.isRelocatable()) break :blk name; | 285 | if (elf_file.base.isRelocatable()) break :blk name; |
| 282 | if (shdr.sh_flags & elf.SHF_MERGE != 0 and shdr.sh_flags & elf.SHF_STRINGS == 0) | 286 | if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; |
| 283 | break :blk name; // TODO: consider dropping SHF_STRINGS once ICF is implemented | ||
| 284 | const sh_name_prefixes: []const [:0]const u8 = &.{ | 287 | const sh_name_prefixes: []const [:0]const u8 = &.{ |
| 285 | ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", | 288 | ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", |
| 286 | ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", | 289 | ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", |
| ... | @@ -334,7 +337,6 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { | ... | @@ -334,7 +337,6 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { |
| 334 | const name = self.getString(shdr.sh_name); | 337 | const name = self.getString(shdr.sh_name); |
| 335 | const ignore = blk: { | 338 | const ignore = blk: { |
| 336 | if (mem.startsWith(u8, name, ".note")) break :blk true; | 339 | if (mem.startsWith(u8, name, ".note")) break :blk true; |
| 337 | if (mem.startsWith(u8, name, ".comment")) break :blk true; | ||
| 338 | if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; | 340 | if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; |
| 339 | if (mem.startsWith(u8, name, ".riscv.attributes")) break :blk true; // TODO: riscv attributes | 341 | if (mem.startsWith(u8, name, ".riscv.attributes")) break :blk true; // TODO: riscv attributes |
| 340 | if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and | 342 | if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and |
| ... | @@ -353,7 +355,7 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { | ... | @@ -353,7 +355,7 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 353 | const index = try elf_file.addSymbol(); | 355 | const index = try elf_file.addSymbol(); |
| 354 | self.symbols.appendAssumeCapacity(index); | 356 | self.symbols.appendAssumeCapacity(index); |
| 355 | const sym_ptr = elf_file.symbol(index); | 357 | const sym_ptr = elf_file.symbol(index); |
| 356 | sym_ptr.value = sym.st_value; | 358 | sym_ptr.value = @intCast(sym.st_value); |
| 357 | sym_ptr.name_offset = sym.st_name; | 359 | sym_ptr.name_offset = sym.st_name; |
| 358 | sym_ptr.esym_index = @as(u32, @intCast(i)); | 360 | sym_ptr.esym_index = @as(u32, @intCast(i)); |
| 359 | sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx]; | 361 | sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx]; |
| ... | @@ -445,13 +447,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: | ... | @@ -445,13 +447,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 445 | while (i < self.fdes.items.len) { | 447 | while (i < self.fdes.items.len) { |
| 446 | const fde = self.fdes.items[i]; | 448 | const fde = self.fdes.items[i]; |
| 447 | const atom = fde.atom(elf_file); | 449 | const atom = fde.atom(elf_file); |
| 448 | atom.fde_start = i; | 450 | const start = i; |
| 449 | i += 1; | 451 | i += 1; |
| 450 | while (i < self.fdes.items.len) : (i += 1) { | 452 | while (i < self.fdes.items.len) : (i += 1) { |
| 451 | const next_fde = self.fdes.items[i]; | 453 | const next_fde = self.fdes.items[i]; |
| 452 | if (atom.atom_index != next_fde.atom(elf_file).atom_index) break; | 454 | if (atom.atom_index != next_fde.atom(elf_file).atom_index) break; |
| 453 | } | 455 | } |
| 454 | atom.fde_end = i; | 456 | try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file); |
| 457 | atom.flags.fde = true; | ||
| 455 | } | 458 | } |
| 456 | } | 459 | } |
| 457 | 460 | ||
| ... | @@ -545,7 +548,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { | ... | @@ -545,7 +548,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { |
| 545 | elf.SHN_ABS, elf.SHN_COMMON => 0, | 548 | elf.SHN_ABS, elf.SHN_COMMON => 0, |
| 546 | else => self.atoms.items[esym.st_shndx], | 549 | else => self.atoms.items[esym.st_shndx], |
| 547 | }; | 550 | }; |
| 548 | global.value = esym.st_value; | 551 | global.value = @intCast(esym.st_value); |
| 549 | global.atom_index = atom_index; | 552 | global.atom_index = atom_index; |
| 550 | global.esym_index = esym_index; | 553 | global.esym_index = esym_index; |
| 551 | global.file_index = self.index; | 554 | global.file_index = self.index; |
| ... | @@ -657,6 +660,178 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO | ... | @@ -657,6 +660,178 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO |
| 657 | } | 660 | } |
| 658 | } | 661 | } |
| 659 | 662 | ||
| 663 | pub fn initMergeSections(self: *Object, elf_file: *Elf) !void { | ||
| 664 | const gpa = elf_file.base.comp.gpa; | ||
| 665 | |||
| 666 | try self.merge_sections.resize(gpa, self.shdrs.items.len); | ||
| 667 | @memset(self.merge_sections.items, 0); | ||
| 668 | |||
| 669 | for (self.shdrs.items, 0..) |shdr, shndx| { | ||
| 670 | if (shdr.sh_flags & elf.SHF_MERGE == 0) continue; | ||
| 671 | |||
| 672 | const atom_index = self.atoms.items[shndx]; | ||
| 673 | const atom_ptr = elf_file.atom(atom_index) orelse continue; | ||
| 674 | if (!atom_ptr.flags.alive) continue; | ||
| 675 | if (atom_ptr.relocs(elf_file).len > 0) continue; | ||
| 676 | |||
| 677 | const imsec_idx = try elf_file.addInputMergeSection(); | ||
| 678 | const imsec = elf_file.inputMergeSection(imsec_idx).?; | ||
| 679 | self.merge_sections.items[shndx] = imsec_idx; | ||
| 680 | |||
| 681 | imsec.merge_section_index = try elf_file.getOrCreateMergeSection(atom_ptr.name(elf_file), shdr.sh_flags, shdr.sh_type); | ||
| 682 | imsec.atom_index = atom_index; | ||
| 683 | |||
| 684 | const data = try self.codeDecompressAlloc(elf_file, atom_index); | ||
| 685 | defer gpa.free(data); | ||
| 686 | |||
| 687 | if (shdr.sh_flags & elf.SHF_STRINGS != 0) { | ||
| 688 | const sh_entsize: u32 = switch (shdr.sh_entsize) { | ||
| 689 | // According to mold's source code, GHC emits MS sections with sh_entsize = 0. | ||
| 690 | // This actually can also happen for output created with `-r` mode. | ||
| 691 | 0 => 1, | ||
| 692 | else => |x| @intCast(x), | ||
| 693 | }; | ||
| 694 | |||
| 695 | const isNull = struct { | ||
| 696 | fn isNull(slice: []u8) bool { | ||
| 697 | for (slice) |x| if (x != 0) return false; | ||
| 698 | return true; | ||
| 699 | } | ||
| 700 | }.isNull; | ||
| 701 | |||
| 702 | var start: u32 = 0; | ||
| 703 | while (start < data.len) { | ||
| 704 | var end = start; | ||
| 705 | while (end < data.len - sh_entsize and !isNull(data[end .. end + sh_entsize])) : (end += sh_entsize) {} | ||
| 706 | if (!isNull(data[end .. end + sh_entsize])) { | ||
| 707 | var err = try elf_file.addErrorWithNotes(1); | ||
| 708 | try err.addMsg(elf_file, "string not null terminated", .{}); | ||
| 709 | try err.addNote(elf_file, "in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); | ||
| 710 | return error.MalformedObject; | ||
| 711 | } | ||
| 712 | end += sh_entsize; | ||
| 713 | const string = data[start..end]; | ||
| 714 | try imsec.insert(gpa, string); | ||
| 715 | try imsec.offsets.append(gpa, start); | ||
| 716 | start = end; | ||
| 717 | } | ||
| 718 | } else { | ||
| 719 | const sh_entsize: u32 = @intCast(shdr.sh_entsize); | ||
| 720 | if (sh_entsize == 0) continue; // Malformed, don't split but don't error out | ||
| 721 | if (shdr.sh_size % sh_entsize != 0) { | ||
| 722 | var err = try elf_file.addErrorWithNotes(1); | ||
| 723 | try err.addMsg(elf_file, "size not a multiple of sh_entsize", .{}); | ||
| 724 | try err.addNote(elf_file, "in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); | ||
| 725 | return error.MalformedObject; | ||
| 726 | } | ||
| 727 | |||
| 728 | var pos: u32 = 0; | ||
| 729 | while (pos < data.len) : (pos += sh_entsize) { | ||
| 730 | const string = data.ptr[pos..][0..sh_entsize]; | ||
| 731 | try imsec.insert(gpa, string); | ||
| 732 | try imsec.offsets.append(gpa, pos); | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | atom_ptr.flags.alive = false; | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 740 | pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { | ||
| 741 | const gpa = elf_file.base.comp.gpa; | ||
| 742 | |||
| 743 | for (self.merge_sections.items) |index| { | ||
| 744 | const imsec = elf_file.inputMergeSection(index) orelse continue; | ||
| 745 | if (imsec.offsets.items.len == 0) continue; | ||
| 746 | const msec = elf_file.mergeSection(imsec.merge_section_index); | ||
| 747 | const atom_ptr = elf_file.atom(imsec.atom_index).?; | ||
| 748 | const isec = atom_ptr.inputShdr(elf_file); | ||
| 749 | |||
| 750 | try imsec.subsections.resize(gpa, imsec.strings.items.len); | ||
| 751 | |||
| 752 | for (imsec.strings.items, imsec.subsections.items) |str, *imsec_msub| { | ||
| 753 | const string = imsec.bytes.items[str.pos..][0..str.len]; | ||
| 754 | const res = try msec.insert(gpa, string); | ||
| 755 | if (!res.found_existing) { | ||
| 756 | const msub_index = try elf_file.addMergeSubsection(); | ||
| 757 | const msub = elf_file.mergeSubsection(msub_index); | ||
| 758 | msub.merge_section_index = imsec.merge_section_index; | ||
| 759 | msub.string_index = res.key.pos; | ||
| 760 | msub.alignment = atom_ptr.alignment; | ||
| 761 | msub.size = res.key.len; | ||
| 762 | msub.entsize = math.cast(u32, isec.sh_entsize) orelse return error.Overflow; | ||
| 763 | msub.alive = !elf_file.base.gc_sections or isec.sh_flags & elf.SHF_ALLOC == 0; | ||
| 764 | res.sub.* = msub_index; | ||
| 765 | } | ||
| 766 | imsec_msub.* = res.sub.*; | ||
| 767 | } | ||
| 768 | |||
| 769 | imsec.clearAndFree(gpa); | ||
| 770 | } | ||
| 771 | |||
| 772 | for (self.symtab.items, 0..) |*esym, idx| { | ||
| 773 | const sym_index = self.symbols.items[idx]; | ||
| 774 | const sym = elf_file.symbol(sym_index); | ||
| 775 | |||
| 776 | if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue; | ||
| 777 | |||
| 778 | const imsec_index = self.merge_sections.items[esym.st_shndx]; | ||
| 779 | const imsec = elf_file.inputMergeSection(imsec_index) orelse continue; | ||
| 780 | if (imsec.offsets.items.len == 0) continue; | ||
| 781 | const msub_index, const offset = imsec.findSubsection(@intCast(esym.st_value)) orelse { | ||
| 782 | var err = try elf_file.addErrorWithNotes(2); | ||
| 783 | try err.addMsg(elf_file, "invalid symbol value: {x}", .{esym.st_value}); | ||
| 784 | try err.addNote(elf_file, "for symbol {s}", .{sym.name(elf_file)}); | ||
| 785 | try err.addNote(elf_file, "in {}", .{self.fmtPath()}); | ||
| 786 | return error.MalformedObject; | ||
| 787 | }; | ||
| 788 | |||
| 789 | try sym.addExtra(.{ .subsection = msub_index }, elf_file); | ||
| 790 | sym.flags.merge_subsection = true; | ||
| 791 | sym.value = offset; | ||
| 792 | } | ||
| 793 | |||
| 794 | for (self.atoms.items) |atom_index| { | ||
| 795 | const atom_ptr = elf_file.atom(atom_index) orelse continue; | ||
| 796 | if (!atom_ptr.flags.alive) continue; | ||
| 797 | const extras = atom_ptr.extra(elf_file) orelse continue; | ||
| 798 | const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count]; | ||
| 799 | for (relocs) |*rel| { | ||
| 800 | const esym = self.symtab.items[rel.r_sym()]; | ||
| 801 | if (esym.st_type() != elf.STT_SECTION) continue; | ||
| 802 | |||
| 803 | const imsec_index = self.merge_sections.items[esym.st_shndx]; | ||
| 804 | const imsec = elf_file.inputMergeSection(imsec_index) orelse continue; | ||
| 805 | if (imsec.offsets.items.len == 0) continue; | ||
| 806 | const msub_index, const offset = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse { | ||
| 807 | var err = try elf_file.addErrorWithNotes(1); | ||
| 808 | try err.addMsg(elf_file, "invalid relocation at offset 0x{x}", .{rel.r_offset}); | ||
| 809 | try err.addNote(elf_file, "in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); | ||
| 810 | return error.MalformedObject; | ||
| 811 | }; | ||
| 812 | const msub = elf_file.mergeSubsection(msub_index); | ||
| 813 | const msec = msub.mergeSection(elf_file); | ||
| 814 | |||
| 815 | const out_sym_idx: u64 = @intCast(self.symbols.items.len); | ||
| 816 | try self.symbols.ensureUnusedCapacity(gpa, 1); | ||
| 817 | const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), msub_index }); | ||
| 818 | defer gpa.free(name); | ||
| 819 | const sym_index = try elf_file.addSymbol(); | ||
| 820 | const sym = elf_file.symbol(sym_index); | ||
| 821 | sym.* = .{ | ||
| 822 | .value = @bitCast(@as(i64, @intCast(offset)) - rel.r_addend), | ||
| 823 | .name_offset = try self.addString(gpa, name), | ||
| 824 | .esym_index = rel.r_sym(), | ||
| 825 | .file_index = self.index, | ||
| 826 | }; | ||
| 827 | try sym.addExtra(.{ .subsection = msub_index }, elf_file); | ||
| 828 | sym.flags.merge_subsection = true; | ||
| 829 | self.symbols.addOneAssumeCapacity().* = sym_index; | ||
| 830 | rel.r_info = (out_sym_idx << 32) | rel.r_type(); | ||
| 831 | } | ||
| 832 | } | ||
| 833 | } | ||
| 834 | |||
| 660 | /// We will create dummy shdrs per each resolved common symbols to make it | 835 | /// We will create dummy shdrs per each resolved common symbols to make it |
| 661 | /// play nicely with the rest of the system. | 836 | /// play nicely with the rest of the system. |
| 662 | pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { | 837 | pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { |
| ... | @@ -747,6 +922,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { | ... | @@ -747,6 +922,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { |
| 747 | 922 | ||
| 748 | for (self.locals()) |local_index| { | 923 | for (self.locals()) |local_index| { |
| 749 | const local = elf_file.symbol(local_index); | 924 | const local = elf_file.symbol(local_index); |
| 925 | if (local.mergeSubsection(elf_file)) |msub| { | ||
| 926 | if (!msub.alive) continue; | ||
| 927 | local.output_section_index = msub.mergeSection(elf_file).output_section_index; | ||
| 928 | continue; | ||
| 929 | } | ||
| 750 | const atom = local.atom(elf_file) orelse continue; | 930 | const atom = local.atom(elf_file) orelse continue; |
| 751 | if (!atom.flags.alive) continue; | 931 | if (!atom.flags.alive) continue; |
| 752 | local.output_section_index = atom.output_section_index; | 932 | local.output_section_index = atom.output_section_index; |
| ... | @@ -754,11 +934,23 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { | ... | @@ -754,11 +934,23 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { |
| 754 | 934 | ||
| 755 | for (self.globals()) |global_index| { | 935 | for (self.globals()) |global_index| { |
| 756 | const global = elf_file.symbol(global_index); | 936 | const global = elf_file.symbol(global_index); |
| 937 | if (global.file(elf_file).?.index() != self.index) continue; | ||
| 938 | if (global.mergeSubsection(elf_file)) |msub| { | ||
| 939 | if (!msub.alive) continue; | ||
| 940 | global.output_section_index = msub.mergeSection(elf_file).output_section_index; | ||
| 941 | continue; | ||
| 942 | } | ||
| 757 | const atom = global.atom(elf_file) orelse continue; | 943 | const atom = global.atom(elf_file) orelse continue; |
| 758 | if (!atom.flags.alive) continue; | 944 | if (!atom.flags.alive) continue; |
| 759 | if (global.file(elf_file).?.index() != self.index) continue; | ||
| 760 | global.output_section_index = atom.output_section_index; | 945 | global.output_section_index = atom.output_section_index; |
| 761 | } | 946 | } |
| 947 | |||
| 948 | for (self.symbols.items[self.symtab.items.len..]) |local_index| { | ||
| 949 | const local = elf_file.symbol(local_index); | ||
| 950 | const msub = local.mergeSubsection(elf_file).?; | ||
| 951 | if (!msub.alive) continue; | ||
| 952 | local.output_section_index = msub.mergeSection(elf_file).output_section_index; | ||
| 953 | } | ||
| 762 | } | 954 | } |
| 763 | 955 | ||
| 764 | pub fn initRelaSections(self: Object, elf_file: *Elf) !void { | 956 | pub fn initRelaSections(self: Object, elf_file: *Elf) !void { |
| ... | @@ -843,9 +1035,17 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { | ... | @@ -843,9 +1035,17 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { |
| 843 | } | 1035 | } |
| 844 | 1036 | ||
| 845 | pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { | 1037 | pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| 1038 | const isAlive = struct { | ||
| 1039 | fn isAlive(sym: *const Symbol, ctx: *Elf) bool { | ||
| 1040 | if (sym.mergeSubsection(ctx)) |msub| return msub.alive; | ||
| 1041 | if (sym.atom(ctx)) |atom_ptr| return atom_ptr.flags.alive; | ||
| 1042 | return true; | ||
| 1043 | } | ||
| 1044 | }.isAlive; | ||
| 1045 | |||
| 846 | for (self.locals()) |local_index| { | 1046 | for (self.locals()) |local_index| { |
| 847 | const local = elf_file.symbol(local_index); | 1047 | const local = elf_file.symbol(local_index); |
| 848 | if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue; | 1048 | if (!isAlive(local, elf_file)) continue; |
| 849 | const esym = local.elfSym(elf_file); | 1049 | const esym = local.elfSym(elf_file); |
| 850 | switch (esym.st_type()) { | 1050 | switch (esym.st_type()) { |
| 851 | elf.STT_SECTION => continue, | 1051 | elf.STT_SECTION => continue, |
| ... | @@ -853,7 +1053,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { | ... | @@ -853,7 +1053,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| 853 | else => {}, | 1053 | else => {}, |
| 854 | } | 1054 | } |
| 855 | local.flags.output_symtab = true; | 1055 | local.flags.output_symtab = true; |
| 856 | try local.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file); | 1056 | try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); |
| 857 | self.output_symtab_ctx.nlocals += 1; | 1057 | self.output_symtab_ctx.nlocals += 1; |
| 858 | self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; | 1058 | self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; |
| 859 | } | 1059 | } |
| ... | @@ -862,13 +1062,13 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { | ... | @@ -862,13 +1062,13 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| 862 | const global = elf_file.symbol(global_index); | 1062 | const global = elf_file.symbol(global_index); |
| 863 | const file_ptr = global.file(elf_file) orelse continue; | 1063 | const file_ptr = global.file(elf_file) orelse continue; |
| 864 | if (file_ptr.index() != self.index) continue; | 1064 | if (file_ptr.index() != self.index) continue; |
| 865 | if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue; | 1065 | if (!isAlive(global, elf_file)) continue; |
| 866 | global.flags.output_symtab = true; | 1066 | global.flags.output_symtab = true; |
| 867 | if (global.isLocal(elf_file)) { | 1067 | if (global.isLocal(elf_file)) { |
| 868 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file); | 1068 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); |
| 869 | self.output_symtab_ctx.nlocals += 1; | 1069 | self.output_symtab_ctx.nlocals += 1; |
| 870 | } else { | 1070 | } else { |
| 871 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file); | 1071 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); |
| 872 | self.output_symtab_ctx.nglobals += 1; | 1072 | self.output_symtab_ctx.nglobals += 1; |
| 873 | } | 1073 | } |
| 874 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; | 1074 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; |
| ... | @@ -902,14 +1102,16 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { | ... | @@ -902,14 +1102,16 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { |
| 902 | 1102 | ||
| 903 | pub fn locals(self: Object) []const Symbol.Index { | 1103 | pub fn locals(self: Object) []const Symbol.Index { |
| 904 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; | 1104 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; |
| 905 | const end = self.first_global orelse self.symbols.items.len; | 1105 | assert(self.symbols.items.len >= self.symtab.items.len); |
| 1106 | const end = self.first_global orelse self.symtab.items.len; | ||
| 906 | return self.symbols.items[0..end]; | 1107 | return self.symbols.items[0..end]; |
| 907 | } | 1108 | } |
| 908 | 1109 | ||
| 909 | pub fn globals(self: Object) []const Symbol.Index { | 1110 | pub fn globals(self: Object) []const Symbol.Index { |
| 910 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; | 1111 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; |
| 911 | const start = self.first_global orelse self.symbols.items.len; | 1112 | assert(self.symbols.items.len >= self.symtab.items.len); |
| 912 | return self.symbols.items[start..]; | 1113 | const start = self.first_global orelse self.symtab.items.len; |
| 1114 | return self.symbols.items[start..self.symtab.items.len]; | ||
| 913 | } | 1115 | } |
| 914 | 1116 | ||
| 915 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). | 1117 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). |
| ... | @@ -954,6 +1156,14 @@ pub fn getString(self: Object, off: u32) [:0]const u8 { | ... | @@ -954,6 +1156,14 @@ pub fn getString(self: Object, off: u32) [:0]const u8 { |
| 954 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | 1156 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 955 | } | 1157 | } |
| 956 | 1158 | ||
| 1159 | fn addString(self: *Object, allocator: Allocator, str: []const u8) !u32 { | ||
| 1160 | const off: u32 = @intCast(self.strtab.items.len); | ||
| 1161 | try self.strtab.ensureUnusedCapacity(allocator, str.len + 1); | ||
| 1162 | self.strtab.appendSliceAssumeCapacity(str); | ||
| 1163 | self.strtab.appendAssumeCapacity(0); | ||
| 1164 | return off; | ||
| 1165 | } | ||
| 1166 | |||
| 957 | /// Caller owns the memory. | 1167 | /// Caller owns the memory. |
| 958 | fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { | 1168 | fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { |
| 959 | assert(index < self.shdrs.items.len); | 1169 | assert(index < self.shdrs.items.len); |
| ... | @@ -1159,5 +1369,6 @@ const Cie = eh_frame.Cie; | ... | @@ -1159,5 +1369,6 @@ const Cie = eh_frame.Cie; |
| 1159 | const Elf = @import("../Elf.zig"); | 1369 | const Elf = @import("../Elf.zig"); |
| 1160 | const Fde = eh_frame.Fde; | 1370 | const Fde = eh_frame.Fde; |
| 1161 | const File = @import("file.zig").File; | 1371 | const File = @import("file.zig").File; |
| 1372 | const InputMergeSection = @import("merge_section.zig").InputMergeSection; | ||
| 1162 | const Symbol = @import("Symbol.zig"); | 1373 | const Symbol = @import("Symbol.zig"); |
| 1163 | const Alignment = Atom.Alignment; | 1374 | const Alignment = Atom.Alignment; |
src/link/Elf/SharedObject.zig+2-2| ... | @@ -231,7 +231,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void { | ... | @@ -231,7 +231,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void { |
| 231 | 231 | ||
| 232 | const global = elf_file.symbol(index); | 232 | const global = elf_file.symbol(index); |
| 233 | if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) { | 233 | if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) { |
| 234 | global.value = this_sym.st_value; | 234 | global.value = @intCast(this_sym.st_value); |
| 235 | global.atom_index = 0; | 235 | global.atom_index = 0; |
| 236 | global.esym_index = esym_index; | 236 | global.esym_index = esym_index; |
| 237 | global.version_index = self.versyms.items[esym_index]; | 237 | global.version_index = self.versyms.items[esym_index]; |
| ... | @@ -269,7 +269,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void { | ... | @@ -269,7 +269,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void { |
| 269 | if (file_ptr.index() != self.index) continue; | 269 | if (file_ptr.index() != self.index) continue; |
| 270 | if (global.isLocal(elf_file)) continue; | 270 | if (global.isLocal(elf_file)) continue; |
| 271 | global.flags.output_symtab = true; | 271 | global.flags.output_symtab = true; |
| 272 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file); | 272 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); |
| 273 | self.output_symtab_ctx.nglobals += 1; | 273 | self.output_symtab_ctx.nglobals += 1; |
| 274 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; | 274 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; |
| 275 | } | 275 | } |
src/link/Elf/Symbol.zig+67-31| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | //! Represents a defined symbol. | 1 | //! Represents a defined symbol. |
| 2 | 2 | ||
| 3 | /// Allocated address value of this symbol. | 3 | /// Allocated address value of this symbol. |
| 4 | value: u64 = 0, | 4 | value: i64 = 0, |
| 5 | 5 | ||
| 6 | /// Offset into the linker's string table. | 6 | /// Offset into the linker's string table. |
| 7 | name_offset: u32 = 0, | 7 | name_offset: u32 = 0, |
| ... | @@ -14,7 +14,7 @@ file_index: File.Index = 0, | ... | @@ -14,7 +14,7 @@ file_index: File.Index = 0, |
| 14 | /// Use `atom` to get the pointer to the atom. | 14 | /// Use `atom` to get the pointer to the atom. |
| 15 | atom_index: Atom.Index = 0, | 15 | atom_index: Atom.Index = 0, |
| 16 | 16 | ||
| 17 | /// Assigned output section index for this atom. | 17 | /// Assigned output section index for this symbol. |
| 18 | output_section_index: u32 = 0, | 18 | output_section_index: u32 = 0, |
| 19 | 19 | ||
| 20 | /// Index of the source symbol this symbol references. | 20 | /// Index of the source symbol this symbol references. |
| ... | @@ -33,7 +33,8 @@ extra_index: u32 = 0, | ... | @@ -33,7 +33,8 @@ extra_index: u32 = 0, |
| 33 | pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { | 33 | pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { |
| 34 | const file_ptr = symbol.file(elf_file).?; | 34 | const file_ptr = symbol.file(elf_file).?; |
| 35 | if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS; | 35 | if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS; |
| 36 | return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and | 36 | return !symbol.flags.import and symbol.atom(elf_file) == null and |
| 37 | symbol.mergeSubsection(elf_file) == null and symbol.outputShndx() == null and | ||
| 37 | file_ptr != .linker_defined; | 38 | file_ptr != .linker_defined; |
| 38 | } | 39 | } |
| 39 | 40 | ||
| ... | @@ -70,6 +71,12 @@ pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom { | ... | @@ -70,6 +71,12 @@ pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom { |
| 70 | return elf_file.atom(symbol.atom_index); | 71 | return elf_file.atom(symbol.atom_index); |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 74 | pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection { | ||
| 75 | if (!symbol.flags.merge_subsection) return null; | ||
| 76 | const extras = symbol.extra(elf_file).?; | ||
| 77 | return elf_file.mergeSubsection(extras.subsection); | ||
| 78 | } | ||
| 79 | |||
| 73 | pub fn file(symbol: Symbol, elf_file: *Elf) ?File { | 80 | pub fn file(symbol: Symbol, elf_file: *Elf) ?File { |
| 74 | return elf_file.file(symbol.file_index); | 81 | return elf_file.file(symbol.file_index); |
| 75 | } | 82 | } |
| ... | @@ -92,7 +99,11 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { | ... | @@ -92,7 +99,11 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { |
| 92 | return file_ptr.symbolRank(sym, in_archive); | 99 | return file_ptr.symbolRank(sym, in_archive); |
| 93 | } | 100 | } |
| 94 | 101 | ||
| 95 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) u64 { | 102 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 { |
| 103 | if (symbol.mergeSubsection(elf_file)) |msub| { | ||
| 104 | if (!msub.alive) return 0; | ||
| 105 | return msub.address(elf_file) + symbol.value; | ||
| 106 | } | ||
| 96 | if (symbol.flags.has_copy_rel) { | 107 | if (symbol.flags.has_copy_rel) { |
| 97 | return symbol.copyRelAddress(elf_file); | 108 | return symbol.copyRelAddress(elf_file); |
| 98 | } | 109 | } |
| ... | @@ -108,19 +119,23 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf | ... | @@ -108,19 +119,23 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf |
| 108 | if (!atom_ptr.flags.alive) { | 119 | if (!atom_ptr.flags.alive) { |
| 109 | if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) { | 120 | if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) { |
| 110 | const sym_name = symbol.name(elf_file); | 121 | const sym_name = symbol.name(elf_file); |
| 122 | const sh_addr, const sh_size = blk: { | ||
| 123 | const shndx = elf_file.eh_frame_section_index orelse break :blk .{ 0, 0 }; | ||
| 124 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 125 | break :blk .{ shdr.sh_addr, shdr.sh_size }; | ||
| 126 | }; | ||
| 111 | if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or | 127 | if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or |
| 112 | mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or | 128 | mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or |
| 113 | mem.startsWith(u8, sym_name, ".eh_frame_seg") or | 129 | mem.startsWith(u8, sym_name, ".eh_frame_seg") or |
| 114 | symbol.elfSym(elf_file).st_type() == elf.STT_SECTION) | 130 | symbol.elfSym(elf_file).st_type() == elf.STT_SECTION) |
| 115 | { | 131 | { |
| 116 | return elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr; | 132 | return @intCast(sh_addr); |
| 117 | } | 133 | } |
| 118 | 134 | ||
| 119 | if (mem.startsWith(u8, sym_name, "__FRAME_END__") or | 135 | if (mem.startsWith(u8, sym_name, "__FRAME_END__") or |
| 120 | mem.startsWith(u8, sym_name, "__EH_FRAME_LIST_END__")) | 136 | mem.startsWith(u8, sym_name, "__EH_FRAME_LIST_END__")) |
| 121 | { | 137 | { |
| 122 | const shdr = elf_file.shdrs.items[elf_file.eh_frame_section_index.?]; | 138 | return @intCast(sh_addr + sh_size); |
| 123 | return shdr.sh_addr + shdr.sh_size; | ||
| 124 | } | 139 | } |
| 125 | 140 | ||
| 126 | // TODO I think we potentially should error here | 141 | // TODO I think we potentially should error here |
| ... | @@ -143,65 +158,57 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 { | ... | @@ -143,65 +158,57 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 { |
| 143 | return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal; | 158 | return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal; |
| 144 | } | 159 | } |
| 145 | 160 | ||
| 146 | pub fn setOutputSymtabIndex(symbol: *Symbol, index: u32, elf_file: *Elf) !void { | 161 | pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 147 | if (symbol.extra(elf_file)) |extras| { | ||
| 148 | var new_extras = extras; | ||
| 149 | new_extras.symtab = index; | ||
| 150 | symbol.setExtra(new_extras, elf_file); | ||
| 151 | } else try symbol.addExtra(.{ .symtab = index }, elf_file); | ||
| 152 | } | ||
| 153 | |||
| 154 | pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 { | ||
| 155 | if (!symbol.flags.has_got) return 0; | 162 | if (!symbol.flags.has_got) return 0; |
| 156 | const extras = symbol.extra(elf_file).?; | 163 | const extras = symbol.extra(elf_file).?; |
| 157 | const entry = elf_file.got.entries.items[extras.got]; | 164 | const entry = elf_file.got.entries.items[extras.got]; |
| 158 | return entry.address(elf_file); | 165 | return entry.address(elf_file); |
| 159 | } | 166 | } |
| 160 | 167 | ||
| 161 | pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) u64 { | 168 | pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 162 | if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0; | 169 | if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0; |
| 163 | const extras = symbol.extra(elf_file).?; | 170 | const extras = symbol.extra(elf_file).?; |
| 164 | const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; | 171 | const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; |
| 165 | const cpu_arch = elf_file.getTarget().cpu.arch; | 172 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 166 | return shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch); | 173 | return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch)); |
| 167 | } | 174 | } |
| 168 | 175 | ||
| 169 | pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 { | 176 | pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 170 | if (!symbol.flags.has_plt) return 0; | 177 | if (!symbol.flags.has_plt) return 0; |
| 171 | const extras = symbol.extra(elf_file).?; | 178 | const extras = symbol.extra(elf_file).?; |
| 172 | const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; | 179 | const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; |
| 173 | const cpu_arch = elf_file.getTarget().cpu.arch; | 180 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 174 | return shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch); | 181 | return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch)); |
| 175 | } | 182 | } |
| 176 | 183 | ||
| 177 | pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) u64 { | 184 | pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 178 | if (!symbol.flags.has_plt) return 0; | 185 | if (!symbol.flags.has_plt) return 0; |
| 179 | const extras = symbol.extra(elf_file).?; | 186 | const extras = symbol.extra(elf_file).?; |
| 180 | const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?]; | 187 | const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?]; |
| 181 | return shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size; | 188 | return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size); |
| 182 | } | 189 | } |
| 183 | 190 | ||
| 184 | pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) u64 { | 191 | pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 185 | if (!symbol.flags.has_copy_rel) return 0; | 192 | if (!symbol.flags.has_copy_rel) return 0; |
| 186 | const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?]; | 193 | const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?]; |
| 187 | return shdr.sh_addr + symbol.value; | 194 | return @as(i64, @intCast(shdr.sh_addr)) + symbol.value; |
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 { | 197 | pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 191 | if (!symbol.flags.has_tlsgd) return 0; | 198 | if (!symbol.flags.has_tlsgd) return 0; |
| 192 | const extras = symbol.extra(elf_file).?; | 199 | const extras = symbol.extra(elf_file).?; |
| 193 | const entry = elf_file.got.entries.items[extras.tlsgd]; | 200 | const entry = elf_file.got.entries.items[extras.tlsgd]; |
| 194 | return entry.address(elf_file); | 201 | return entry.address(elf_file); |
| 195 | } | 202 | } |
| 196 | 203 | ||
| 197 | pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) u64 { | 204 | pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 198 | if (!symbol.flags.has_gottp) return 0; | 205 | if (!symbol.flags.has_gottp) return 0; |
| 199 | const extras = symbol.extra(elf_file).?; | 206 | const extras = symbol.extra(elf_file).?; |
| 200 | const entry = elf_file.got.entries.items[extras.gottp]; | 207 | const entry = elf_file.got.entries.items[extras.gottp]; |
| 201 | return entry.address(elf_file); | 208 | return entry.address(elf_file); |
| 202 | } | 209 | } |
| 203 | 210 | ||
| 204 | pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 { | 211 | pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 205 | if (!symbol.flags.has_tlsdesc) return 0; | 212 | if (!symbol.flags.has_tlsdesc) return 0; |
| 206 | const extras = symbol.extra(elf_file).?; | 213 | const extras = symbol.extra(elf_file).?; |
| 207 | const entry = elf_file.got.entries.items[extras.tlsdesc]; | 214 | const entry = elf_file.got.entries.items[extras.tlsdesc]; |
| ... | @@ -221,7 +228,7 @@ pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *E | ... | @@ -221,7 +228,7 @@ pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *E |
| 221 | return .{ .found_existing = false, .index = index }; | 228 | return .{ .found_existing = false, .index = index }; |
| 222 | } | 229 | } |
| 223 | 230 | ||
| 224 | pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) u64 { | 231 | pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 225 | if (!symbol.flags.has_zig_got) return 0; | 232 | if (!symbol.flags.has_zig_got) return 0; |
| 226 | const extras = symbol.extra(elf_file).?; | 233 | const extras = symbol.extra(elf_file).?; |
| 227 | return elf_file.zig_got.entryAddress(extras.zig_got, elf_file); | 234 | return elf_file.zig_got.entryAddress(extras.zig_got, elf_file); |
| ... | @@ -240,8 +247,31 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { | ... | @@ -240,8 +247,31 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { |
| 240 | @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value))); | 247 | @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value))); |
| 241 | } | 248 | } |
| 242 | 249 | ||
| 243 | pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void { | 250 | const AddExtraOpts = struct { |
| 244 | symbol.extra_index = try elf_file.addSymbolExtra(extras); | 251 | got: ?u32 = null, |
| 252 | plt: ?u32 = null, | ||
| 253 | plt_got: ?u32 = null, | ||
| 254 | dynamic: ?u32 = null, | ||
| 255 | symtab: ?u32 = null, | ||
| 256 | copy_rel: ?u32 = null, | ||
| 257 | tlsgd: ?u32 = null, | ||
| 258 | gottp: ?u32 = null, | ||
| 259 | tlsdesc: ?u32 = null, | ||
| 260 | zig_got: ?u32 = null, | ||
| 261 | subsection: ?u32 = null, | ||
| 262 | }; | ||
| 263 | |||
| 264 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { | ||
| 265 | if (symbol.extra(elf_file) == null) { | ||
| 266 | symbol.extra_index = try elf_file.addSymbolExtra(.{}); | ||
| 267 | } | ||
| 268 | var extras = symbol.extra(elf_file).?; | ||
| 269 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { | ||
| 270 | if (@field(opts, field.name)) |x| { | ||
| 271 | @field(extras, field.name) = x; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | symbol.setExtra(extras, elf_file); | ||
| 245 | } | 275 | } |
| 246 | 276 | ||
| 247 | pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra { | 277 | pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra { |
| ... | @@ -266,6 +296,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { | ... | @@ -266,6 +296,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 266 | if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.copy_rel_section_index.?); | 296 | if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.copy_rel_section_index.?); |
| 267 | if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; | 297 | if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; |
| 268 | if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON; | 298 | if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON; |
| 299 | if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index); | ||
| 269 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; | 300 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; |
| 270 | break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF); | 301 | break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF); |
| 271 | }; | 302 | }; |
| ... | @@ -284,7 +315,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { | ... | @@ -284,7 +315,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 284 | out.st_info = (st_bind << 4) | st_type; | 315 | out.st_info = (st_bind << 4) | st_type; |
| 285 | out.st_other = esym.st_other; | 316 | out.st_other = esym.st_other; |
| 286 | out.st_shndx = st_shndx; | 317 | out.st_shndx = st_shndx; |
| 287 | out.st_value = st_value; | 318 | out.st_value = @intCast(st_value); |
| 288 | out.st_size = esym.st_size; | 319 | out.st_size = esym.st_size; |
| 289 | } | 320 | } |
| 290 | 321 | ||
| ... | @@ -436,6 +467,9 @@ pub const Flags = packed struct { | ... | @@ -436,6 +467,9 @@ pub const Flags = packed struct { |
| 436 | /// TODO this is really not needed if only we operated on esyms between | 467 | /// TODO this is really not needed if only we operated on esyms between |
| 437 | /// codegen and ZigObject. | 468 | /// codegen and ZigObject. |
| 438 | is_tls: bool = false, | 469 | is_tls: bool = false, |
| 470 | |||
| 471 | /// Whether the symbol is a merge subsection. | ||
| 472 | merge_subsection: bool = false, | ||
| 439 | }; | 473 | }; |
| 440 | 474 | ||
| 441 | pub const Extra = struct { | 475 | pub const Extra = struct { |
| ... | @@ -449,6 +483,7 @@ pub const Extra = struct { | ... | @@ -449,6 +483,7 @@ pub const Extra = struct { |
| 449 | gottp: u32 = 0, | 483 | gottp: u32 = 0, |
| 450 | tlsdesc: u32 = 0, | 484 | tlsdesc: u32 = 0, |
| 451 | zig_got: u32 = 0, | 485 | zig_got: u32 = 0, |
| 486 | subsection: u32 = 0, | ||
| 452 | }; | 487 | }; |
| 453 | 488 | ||
| 454 | pub const Index = u32; | 489 | pub const Index = u32; |
| ... | @@ -465,6 +500,7 @@ const File = @import("file.zig").File; | ... | @@ -465,6 +500,7 @@ const File = @import("file.zig").File; |
| 465 | const GotSection = synthetic_sections.GotSection; | 500 | const GotSection = synthetic_sections.GotSection; |
| 466 | const GotPltSection = synthetic_sections.GotPltSection; | 501 | const GotPltSection = synthetic_sections.GotPltSection; |
| 467 | const LinkerDefined = @import("LinkerDefined.zig"); | 502 | const LinkerDefined = @import("LinkerDefined.zig"); |
| 503 | const MergeSubsection = @import("merge_section.zig").MergeSubsection; | ||
| 468 | const Object = @import("Object.zig"); | 504 | const Object = @import("Object.zig"); |
| 469 | const PltSection = synthetic_sections.PltSection; | 505 | const PltSection = synthetic_sections.PltSection; |
| 470 | const PltGotSection = synthetic_sections.PltGotSection; | 506 | const PltGotSection = synthetic_sections.PltGotSection; |
src/link/Elf/ZigObject.zig+14-14| ... | @@ -343,7 +343,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { | ... | @@ -343,7 +343,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { |
| 343 | atom.outputShndx().? | 343 | atom.outputShndx().? |
| 344 | else | 344 | else |
| 345 | elf.SHN_UNDEF; | 345 | elf.SHN_UNDEF; |
| 346 | global.value = esym.st_value; | 346 | global.value = @intCast(esym.st_value); |
| 347 | global.atom_index = atom_index; | 347 | global.atom_index = atom_index; |
| 348 | global.esym_index = esym_index; | 348 | global.esym_index = esym_index; |
| 349 | global.file_index = self.index; | 349 | global.file_index = self.index; |
| ... | @@ -566,7 +566,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { | ... | @@ -566,7 +566,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { |
| 566 | else => {}, | 566 | else => {}, |
| 567 | } | 567 | } |
| 568 | local.flags.output_symtab = true; | 568 | local.flags.output_symtab = true; |
| 569 | try local.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file); | 569 | try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); |
| 570 | self.output_symtab_ctx.nlocals += 1; | 570 | self.output_symtab_ctx.nlocals += 1; |
| 571 | self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; | 571 | self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; |
| 572 | } | 572 | } |
| ... | @@ -578,10 +578,10 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { | ... | @@ -578,10 +578,10 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { |
| 578 | if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue; | 578 | if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue; |
| 579 | global.flags.output_symtab = true; | 579 | global.flags.output_symtab = true; |
| 580 | if (global.isLocal(elf_file)) { | 580 | if (global.isLocal(elf_file)) { |
| 581 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file); | 581 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); |
| 582 | self.output_symtab_ctx.nlocals += 1; | 582 | self.output_symtab_ctx.nlocals += 1; |
| 583 | } else { | 583 | } else { |
| 584 | try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file); | 584 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); |
| 585 | self.output_symtab_ctx.nglobals += 1; | 585 | self.output_symtab_ctx.nglobals += 1; |
| 586 | } | 586 | } |
| 587 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; | 587 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; |
| ... | @@ -631,7 +631,7 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 | ... | @@ -631,7 +631,7 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 |
| 631 | return code; | 631 | return code; |
| 632 | } | 632 | } |
| 633 | 633 | ||
| 634 | const file_offset = shdr.sh_offset + atom.value; | 634 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value)); |
| 635 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | 635 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; |
| 636 | const code = try gpa.alloc(u8, size); | 636 | const code = try gpa.alloc(u8, size); |
| 637 | errdefer gpa.free(code); | 637 | errdefer gpa.free(code); |
| ... | @@ -659,7 +659,7 @@ pub fn getDeclVAddr( | ... | @@ -659,7 +659,7 @@ pub fn getDeclVAddr( |
| 659 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, | 659 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, |
| 660 | .r_addend = reloc_info.addend, | 660 | .r_addend = reloc_info.addend, |
| 661 | }); | 661 | }); |
| 662 | return vaddr; | 662 | return @intCast(vaddr); |
| 663 | } | 663 | } |
| 664 | 664 | ||
| 665 | pub fn getAnonDeclVAddr( | 665 | pub fn getAnonDeclVAddr( |
| ... | @@ -678,7 +678,7 @@ pub fn getAnonDeclVAddr( | ... | @@ -678,7 +678,7 @@ pub fn getAnonDeclVAddr( |
| 678 | .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, | 678 | .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, |
| 679 | .r_addend = reloc_info.addend, | 679 | .r_addend = reloc_info.addend, |
| 680 | }); | 680 | }); |
| 681 | return vaddr; | 681 | return @intCast(vaddr); |
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | pub fn lowerAnonDecl( | 684 | pub fn lowerAnonDecl( |
| ... | @@ -929,7 +929,7 @@ fn updateDeclCode( | ... | @@ -929,7 +929,7 @@ fn updateDeclCode( |
| 929 | 929 | ||
| 930 | if (old_size > 0 and elf_file.base.child_pid == null) { | 930 | if (old_size > 0 and elf_file.base.child_pid == null) { |
| 931 | const capacity = atom_ptr.capacity(elf_file); | 931 | const capacity = atom_ptr.capacity(elf_file); |
| 932 | const need_realloc = code.len > capacity or !required_alignment.check(atom_ptr.value); | 932 | const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value)); |
| 933 | if (need_realloc) { | 933 | if (need_realloc) { |
| 934 | try atom_ptr.grow(elf_file); | 934 | try atom_ptr.grow(elf_file); |
| 935 | log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom_ptr.value }); | 935 | log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom_ptr.value }); |
| ... | @@ -984,7 +984,7 @@ fn updateDeclCode( | ... | @@ -984,7 +984,7 @@ fn updateDeclCode( |
| 984 | 984 | ||
| 985 | const shdr = elf_file.shdrs.items[shdr_index]; | 985 | const shdr = elf_file.shdrs.items[shdr_index]; |
| 986 | if (shdr.sh_type != elf.SHT_NOBITS) { | 986 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 987 | const file_offset = shdr.sh_offset + atom_ptr.value; | 987 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 988 | try elf_file.base.file.?.pwriteAll(code, file_offset); | 988 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 989 | } | 989 | } |
| 990 | } | 990 | } |
| ... | @@ -1107,7 +1107,7 @@ pub fn updateFunc( | ... | @@ -1107,7 +1107,7 @@ pub fn updateFunc( |
| 1107 | try self.dwarf.?.commitDeclState( | 1107 | try self.dwarf.?.commitDeclState( |
| 1108 | mod, | 1108 | mod, |
| 1109 | decl_index, | 1109 | decl_index, |
| 1110 | sym.address(.{}, elf_file), | 1110 | @intCast(sym.address(.{}, elf_file)), |
| 1111 | sym.atom(elf_file).?.size, | 1111 | sym.atom(elf_file).?.size, |
| 1112 | ds, | 1112 | ds, |
| 1113 | ); | 1113 | ); |
| ... | @@ -1186,7 +1186,7 @@ pub fn updateDecl( | ... | @@ -1186,7 +1186,7 @@ pub fn updateDecl( |
| 1186 | try self.dwarf.?.commitDeclState( | 1186 | try self.dwarf.?.commitDeclState( |
| 1187 | mod, | 1187 | mod, |
| 1188 | decl_index, | 1188 | decl_index, |
| 1189 | sym.address(.{}, elf_file), | 1189 | @intCast(sym.address(.{}, elf_file)), |
| 1190 | sym.atom(elf_file).?.size, | 1190 | sym.atom(elf_file).?.size, |
| 1191 | ds, | 1191 | ds, |
| 1192 | ); | 1192 | ); |
| ... | @@ -1275,7 +1275,7 @@ fn updateLazySymbol( | ... | @@ -1275,7 +1275,7 @@ fn updateLazySymbol( |
| 1275 | } | 1275 | } |
| 1276 | 1276 | ||
| 1277 | const shdr = elf_file.shdrs.items[output_section_index]; | 1277 | const shdr = elf_file.shdrs.items[output_section_index]; |
| 1278 | const file_offset = shdr.sh_offset + atom_ptr.value; | 1278 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1279 | try elf_file.base.file.?.pwriteAll(code, file_offset); | 1279 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 1280 | } | 1280 | } |
| 1281 | 1281 | ||
| ... | @@ -1373,7 +1373,7 @@ fn lowerConst( | ... | @@ -1373,7 +1373,7 @@ fn lowerConst( |
| 1373 | local_esym.st_value = 0; | 1373 | local_esym.st_value = 0; |
| 1374 | 1374 | ||
| 1375 | const shdr = elf_file.shdrs.items[output_section_index]; | 1375 | const shdr = elf_file.shdrs.items[output_section_index]; |
| 1376 | const file_offset = shdr.sh_offset + atom_ptr.value; | 1376 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1377 | try elf_file.base.file.?.pwriteAll(code, file_offset); | 1377 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 1378 | 1378 | ||
| 1379 | return .{ .ok = sym_index }; | 1379 | return .{ .ok = sym_index }; |
| ... | @@ -1457,7 +1457,7 @@ pub fn updateExports( | ... | @@ -1457,7 +1457,7 @@ pub fn updateExports( |
| 1457 | 1457 | ||
| 1458 | const actual_esym_index = global_esym_index & symbol_mask; | 1458 | const actual_esym_index = global_esym_index & symbol_mask; |
| 1459 | const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index]; | 1459 | const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index]; |
| 1460 | global_esym.st_value = elf_file.symbol(sym_index).value; | 1460 | global_esym.st_value = @intCast(elf_file.symbol(sym_index).value); |
| 1461 | global_esym.st_shndx = esym.st_shndx; | 1461 | global_esym.st_shndx = esym.st_shndx; |
| 1462 | global_esym.st_info = (stb_bits << 4) | stt_bits; | 1462 | global_esym.st_info = (stb_bits << 4) | stt_bits; |
| 1463 | global_esym.st_name = name_off; | 1463 | global_esym.st_name = name_off; |
src/link/Elf/gc.zig+8| ... | @@ -68,6 +68,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil | ... | @@ -68,6 +68,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void { | 70 | fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void { |
| 71 | if (sym.mergeSubsection(elf_file)) |msub| { | ||
| 72 | msub.alive = true; | ||
| 73 | return; | ||
| 74 | } | ||
| 71 | const atom = sym.atom(elf_file) orelse return; | 75 | const atom = sym.atom(elf_file) orelse return; |
| 72 | if (markAtom(atom)) try roots.append(atom); | 76 | if (markAtom(atom)) try roots.append(atom); |
| 73 | } | 77 | } |
| ... | @@ -96,6 +100,10 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { | ... | @@ -96,6 +100,10 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { |
| 96 | 100 | ||
| 97 | for (atom.relocs(elf_file)) |rel| { | 101 | for (atom.relocs(elf_file)) |rel| { |
| 98 | const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); | 102 | const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); |
| 103 | if (target_sym.mergeSubsection(elf_file)) |msub| { | ||
| 104 | msub.alive = true; | ||
| 105 | continue; | ||
| 106 | } | ||
| 99 | const target_atom = target_sym.atom(elf_file) orelse continue; | 107 | const target_atom = target_sym.atom(elf_file) orelse continue; |
| 100 | target_atom.flags.alive = true; | 108 | target_atom.flags.alive = true; |
| 101 | gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); | 109 | gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); |
src/link/Elf/merge_section.zig created+285| ... | @@ -0,0 +1,285 @@ | ||
| 1 | pub const MergeSection = struct { | ||
| 2 | name_offset: u32 = 0, | ||
| 3 | type: u32 = 0, | ||
| 4 | flags: u64 = 0, | ||
| 5 | output_section_index: u32 = 0, | ||
| 6 | bytes: std.ArrayListUnmanaged(u8) = .{}, | ||
| 7 | table: std.HashMapUnmanaged( | ||
| 8 | String, | ||
| 9 | MergeSubsection.Index, | ||
| 10 | IndexContext, | ||
| 11 | std.hash_map.default_max_load_percentage, | ||
| 12 | ) = .{}, | ||
| 13 | subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{}, | ||
| 14 | |||
| 15 | pub fn deinit(msec: *MergeSection, allocator: Allocator) void { | ||
| 16 | msec.bytes.deinit(allocator); | ||
| 17 | msec.table.deinit(allocator); | ||
| 18 | msec.subsections.deinit(allocator); | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn name(msec: MergeSection, elf_file: *Elf) [:0]const u8 { | ||
| 22 | return elf_file.strings.getAssumeExists(msec.name_offset); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub fn address(msec: MergeSection, elf_file: *Elf) i64 { | ||
| 26 | const shdr = elf_file.shdrs.items[msec.output_section_index]; | ||
| 27 | return @intCast(shdr.sh_addr); | ||
| 28 | } | ||
| 29 | |||
| 30 | const InsertResult = struct { | ||
| 31 | found_existing: bool, | ||
| 32 | key: String, | ||
| 33 | sub: *MergeSubsection.Index, | ||
| 34 | }; | ||
| 35 | |||
| 36 | pub fn insert(msec: *MergeSection, allocator: Allocator, string: []const u8) !InsertResult { | ||
| 37 | const gop = try msec.table.getOrPutContextAdapted( | ||
| 38 | allocator, | ||
| 39 | string, | ||
| 40 | IndexAdapter{ .bytes = msec.bytes.items }, | ||
| 41 | IndexContext{ .bytes = msec.bytes.items }, | ||
| 42 | ); | ||
| 43 | if (!gop.found_existing) { | ||
| 44 | const index: u32 = @intCast(msec.bytes.items.len); | ||
| 45 | try msec.bytes.appendSlice(allocator, string); | ||
| 46 | gop.key_ptr.* = .{ .pos = index, .len = @intCast(string.len) }; | ||
| 47 | } | ||
| 48 | return .{ .found_existing = gop.found_existing, .key = gop.key_ptr.*, .sub = gop.value_ptr }; | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn insertZ(msec: *MergeSection, allocator: Allocator, string: []const u8) !InsertResult { | ||
| 52 | const with_null = try allocator.alloc(u8, string.len + 1); | ||
| 53 | defer allocator.free(with_null); | ||
| 54 | @memcpy(with_null[0..string.len], string); | ||
| 55 | with_null[string.len] = 0; | ||
| 56 | return msec.insert(allocator, with_null); | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Finalizes the merge section and clears hash table. | ||
| 60 | /// Sorts all owned subsections. | ||
| 61 | pub fn finalize(msec: *MergeSection, elf_file: *Elf) !void { | ||
| 62 | const gpa = elf_file.base.comp.gpa; | ||
| 63 | try msec.subsections.ensureTotalCapacityPrecise(gpa, msec.table.count()); | ||
| 64 | |||
| 65 | var it = msec.table.iterator(); | ||
| 66 | while (it.next()) |entry| { | ||
| 67 | const msub = elf_file.mergeSubsection(entry.value_ptr.*); | ||
| 68 | if (!msub.alive) continue; | ||
| 69 | msec.subsections.appendAssumeCapacity(entry.value_ptr.*); | ||
| 70 | } | ||
| 71 | msec.table.clearAndFree(gpa); | ||
| 72 | |||
| 73 | const sortFn = struct { | ||
| 74 | pub fn sortFn(ctx: *Elf, lhs: MergeSubsection.Index, rhs: MergeSubsection.Index) bool { | ||
| 75 | const lhs_msub = ctx.mergeSubsection(lhs); | ||
| 76 | const rhs_msub = ctx.mergeSubsection(rhs); | ||
| 77 | if (lhs_msub.alignment.compareStrict(.eq, rhs_msub.alignment)) { | ||
| 78 | if (lhs_msub.size == rhs_msub.size) { | ||
| 79 | return mem.order(u8, lhs_msub.getString(ctx), rhs_msub.getString(ctx)) == .lt; | ||
| 80 | } | ||
| 81 | return lhs_msub.size < rhs_msub.size; | ||
| 82 | } | ||
| 83 | return lhs_msub.alignment.compareStrict(.lt, rhs_msub.alignment); | ||
| 84 | } | ||
| 85 | }.sortFn; | ||
| 86 | |||
| 87 | std.mem.sort(MergeSubsection.Index, msec.subsections.items, elf_file, sortFn); | ||
| 88 | } | ||
| 89 | |||
| 90 | pub const IndexContext = struct { | ||
| 91 | bytes: []const u8, | ||
| 92 | |||
| 93 | pub fn eql(_: @This(), a: String, b: String) bool { | ||
| 94 | return a.pos == b.pos; | ||
| 95 | } | ||
| 96 | |||
| 97 | pub fn hash(ctx: @This(), key: String) u64 { | ||
| 98 | const str = ctx.bytes[key.pos..][0..key.len]; | ||
| 99 | return std.hash_map.hashString(str); | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | pub const IndexAdapter = struct { | ||
| 104 | bytes: []const u8, | ||
| 105 | |||
| 106 | pub fn eql(ctx: @This(), a: []const u8, b: String) bool { | ||
| 107 | const str = ctx.bytes[b.pos..][0..b.len]; | ||
| 108 | return mem.eql(u8, a, str); | ||
| 109 | } | ||
| 110 | |||
| 111 | pub fn hash(_: @This(), adapted_key: []const u8) u64 { | ||
| 112 | return std.hash_map.hashString(adapted_key); | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | |||
| 116 | pub fn format( | ||
| 117 | msec: MergeSection, | ||
| 118 | comptime unused_fmt_string: []const u8, | ||
| 119 | options: std.fmt.FormatOptions, | ||
| 120 | writer: anytype, | ||
| 121 | ) !void { | ||
| 122 | _ = msec; | ||
| 123 | _ = unused_fmt_string; | ||
| 124 | _ = options; | ||
| 125 | _ = writer; | ||
| 126 | @compileError("do not format MergeSection directly"); | ||
| 127 | } | ||
| 128 | |||
| 129 | pub fn fmt(msec: MergeSection, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 130 | return .{ .data = .{ | ||
| 131 | .msec = msec, | ||
| 132 | .elf_file = elf_file, | ||
| 133 | } }; | ||
| 134 | } | ||
| 135 | |||
| 136 | const FormatContext = struct { | ||
| 137 | msec: MergeSection, | ||
| 138 | elf_file: *Elf, | ||
| 139 | }; | ||
| 140 | |||
| 141 | pub fn format2( | ||
| 142 | ctx: FormatContext, | ||
| 143 | comptime unused_fmt_string: []const u8, | ||
| 144 | options: std.fmt.FormatOptions, | ||
| 145 | writer: anytype, | ||
| 146 | ) !void { | ||
| 147 | _ = options; | ||
| 148 | _ = unused_fmt_string; | ||
| 149 | const msec = ctx.msec; | ||
| 150 | const elf_file = ctx.elf_file; | ||
| 151 | try writer.print("{s} : @{x} : type({x}) : flags({x})\n", .{ | ||
| 152 | msec.name(elf_file), | ||
| 153 | msec.address(elf_file), | ||
| 154 | msec.type, | ||
| 155 | msec.flags, | ||
| 156 | }); | ||
| 157 | for (msec.subsections.items) |index| { | ||
| 158 | try writer.print(" {}\n", .{elf_file.mergeSubsection(index).fmt(elf_file)}); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | pub const Index = u32; | ||
| 163 | }; | ||
| 164 | |||
| 165 | pub const MergeSubsection = struct { | ||
| 166 | value: i64 = 0, | ||
| 167 | merge_section_index: MergeSection.Index = 0, | ||
| 168 | string_index: u32 = 0, | ||
| 169 | size: u32 = 0, | ||
| 170 | alignment: Atom.Alignment = .@"1", | ||
| 171 | entsize: u32 = 0, | ||
| 172 | alive: bool = false, | ||
| 173 | |||
| 174 | pub fn address(msub: MergeSubsection, elf_file: *Elf) i64 { | ||
| 175 | return msub.mergeSection(elf_file).address(elf_file) + msub.value; | ||
| 176 | } | ||
| 177 | |||
| 178 | pub fn mergeSection(msub: MergeSubsection, elf_file: *Elf) *MergeSection { | ||
| 179 | return elf_file.mergeSection(msub.merge_section_index); | ||
| 180 | } | ||
| 181 | |||
| 182 | pub fn getString(msub: MergeSubsection, elf_file: *Elf) []const u8 { | ||
| 183 | const msec = msub.mergeSection(elf_file); | ||
| 184 | return msec.bytes.items[msub.string_index..][0..msub.size]; | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn format( | ||
| 188 | msub: MergeSubsection, | ||
| 189 | comptime unused_fmt_string: []const u8, | ||
| 190 | options: std.fmt.FormatOptions, | ||
| 191 | writer: anytype, | ||
| 192 | ) !void { | ||
| 193 | _ = msub; | ||
| 194 | _ = unused_fmt_string; | ||
| 195 | _ = options; | ||
| 196 | _ = writer; | ||
| 197 | @compileError("do not format MergeSubsection directly"); | ||
| 198 | } | ||
| 199 | |||
| 200 | pub fn fmt(msub: MergeSubsection, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 201 | return .{ .data = .{ | ||
| 202 | .msub = msub, | ||
| 203 | .elf_file = elf_file, | ||
| 204 | } }; | ||
| 205 | } | ||
| 206 | |||
| 207 | const FormatContext = struct { | ||
| 208 | msub: MergeSubsection, | ||
| 209 | elf_file: *Elf, | ||
| 210 | }; | ||
| 211 | |||
| 212 | pub fn format2( | ||
| 213 | ctx: FormatContext, | ||
| 214 | comptime unused_fmt_string: []const u8, | ||
| 215 | options: std.fmt.FormatOptions, | ||
| 216 | writer: anytype, | ||
| 217 | ) !void { | ||
| 218 | _ = options; | ||
| 219 | _ = unused_fmt_string; | ||
| 220 | const msub = ctx.msub; | ||
| 221 | const elf_file = ctx.elf_file; | ||
| 222 | try writer.print("@{x} : align({x}) : size({x})", .{ | ||
| 223 | msub.address(elf_file), | ||
| 224 | msub.alignment, | ||
| 225 | msub.size, | ||
| 226 | }); | ||
| 227 | if (!msub.alive) try writer.writeAll(" : [*]"); | ||
| 228 | } | ||
| 229 | |||
| 230 | pub const Index = u32; | ||
| 231 | }; | ||
| 232 | |||
| 233 | pub const InputMergeSection = struct { | ||
| 234 | merge_section_index: MergeSection.Index = 0, | ||
| 235 | atom_index: Atom.Index = 0, | ||
| 236 | offsets: std.ArrayListUnmanaged(u32) = .{}, | ||
| 237 | subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{}, | ||
| 238 | bytes: std.ArrayListUnmanaged(u8) = .{}, | ||
| 239 | strings: std.ArrayListUnmanaged(String) = .{}, | ||
| 240 | |||
| 241 | pub fn deinit(imsec: *InputMergeSection, allocator: Allocator) void { | ||
| 242 | imsec.offsets.deinit(allocator); | ||
| 243 | imsec.subsections.deinit(allocator); | ||
| 244 | imsec.bytes.deinit(allocator); | ||
| 245 | imsec.strings.deinit(allocator); | ||
| 246 | } | ||
| 247 | |||
| 248 | pub fn clearAndFree(imsec: *InputMergeSection, allocator: Allocator) void { | ||
| 249 | imsec.bytes.clearAndFree(allocator); | ||
| 250 | // TODO: imsec.strings.clearAndFree(allocator); | ||
| 251 | } | ||
| 252 | |||
| 253 | pub fn findSubsection(imsec: InputMergeSection, offset: u32) ?struct { MergeSubsection.Index, u32 } { | ||
| 254 | // TODO: binary search | ||
| 255 | for (imsec.offsets.items, 0..) |off, index| { | ||
| 256 | if (offset < off) return .{ | ||
| 257 | imsec.subsections.items[index - 1], | ||
| 258 | offset - imsec.offsets.items[index - 1], | ||
| 259 | }; | ||
| 260 | } | ||
| 261 | const last = imsec.offsets.items.len - 1; | ||
| 262 | const last_off = imsec.offsets.items[last]; | ||
| 263 | const last_len = imsec.strings.items[last].len; | ||
| 264 | if (offset < last_off + last_len) return .{ imsec.subsections.items[last], offset - last_off }; | ||
| 265 | return null; | ||
| 266 | } | ||
| 267 | |||
| 268 | pub fn insert(imsec: *InputMergeSection, allocator: Allocator, string: []const u8) !void { | ||
| 269 | const index: u32 = @intCast(imsec.bytes.items.len); | ||
| 270 | try imsec.bytes.appendSlice(allocator, string); | ||
| 271 | try imsec.strings.append(allocator, .{ .pos = index, .len = @intCast(string.len) }); | ||
| 272 | } | ||
| 273 | |||
| 274 | pub const Index = u32; | ||
| 275 | }; | ||
| 276 | |||
| 277 | const String = struct { pos: u32, len: u32 }; | ||
| 278 | |||
| 279 | const assert = std.debug.assert; | ||
| 280 | const mem = std.mem; | ||
| 281 | const std = @import("std"); | ||
| 282 | |||
| 283 | const Allocator = mem.Allocator; | ||
| 284 | const Atom = @import("Atom.zig"); | ||
| 285 | const Elf = @import("../Elf.zig"); | ||
src/link/Elf/relocatable.zig+13-2| ... | @@ -34,12 +34,16 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co | ... | @@ -34,12 +34,16 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 34 | // First, we flush relocatable object file generated with our backends. | 34 | // First, we flush relocatable object file generated with our backends. |
| 35 | if (elf_file.zigObjectPtr()) |zig_object| { | 35 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 36 | zig_object.resolveSymbols(elf_file); | 36 | zig_object.resolveSymbols(elf_file); |
| 37 | try elf_file.addCommentString(); | ||
| 38 | try elf_file.finalizeMergeSections(); | ||
| 37 | zig_object.claimUnresolvedObject(elf_file); | 39 | zig_object.claimUnresolvedObject(elf_file); |
| 38 | 40 | ||
| 41 | try elf_file.initMergeSections(); | ||
| 39 | try elf_file.initSymtab(); | 42 | try elf_file.initSymtab(); |
| 40 | try elf_file.initShStrtab(); | 43 | try elf_file.initShStrtab(); |
| 41 | try elf_file.sortShdrs(); | 44 | try elf_file.sortShdrs(); |
| 42 | try zig_object.addAtomsToRelaSections(elf_file); | 45 | try zig_object.addAtomsToRelaSections(elf_file); |
| 46 | try elf_file.updateMergeSectionSizes(); | ||
| 43 | try updateSectionSizes(elf_file); | 47 | try updateSectionSizes(elf_file); |
| 44 | 48 | ||
| 45 | try allocateAllocSections(elf_file); | 49 | try allocateAllocSections(elf_file); |
| ... | @@ -49,6 +53,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co | ... | @@ -49,6 +53,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 49 | state_log.debug("{}", .{elf_file.dumpState()}); | 53 | state_log.debug("{}", .{elf_file.dumpState()}); |
| 50 | } | 54 | } |
| 51 | 55 | ||
| 56 | try elf_file.writeMergeSections(); | ||
| 52 | try writeSyntheticSections(elf_file); | 57 | try writeSyntheticSections(elf_file); |
| 53 | try elf_file.writeShdrTable(); | 58 | try elf_file.writeShdrTable(); |
| 54 | try elf_file.writeElfHeader(); | 59 | try elf_file.writeElfHeader(); |
| ... | @@ -179,9 +184,13 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const | ... | @@ -179,9 +184,13 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 179 | // input Object files. | 184 | // input Object files. |
| 180 | elf_file.resolveSymbols(); | 185 | elf_file.resolveSymbols(); |
| 181 | elf_file.markEhFrameAtomsDead(); | 186 | elf_file.markEhFrameAtomsDead(); |
| 187 | try elf_file.resolveMergeSections(); | ||
| 188 | try elf_file.addCommentString(); | ||
| 189 | try elf_file.finalizeMergeSections(); | ||
| 182 | claimUnresolved(elf_file); | 190 | claimUnresolved(elf_file); |
| 183 | 191 | ||
| 184 | try initSections(elf_file); | 192 | try initSections(elf_file); |
| 193 | try elf_file.initMergeSections(); | ||
| 185 | try elf_file.sortShdrs(); | 194 | try elf_file.sortShdrs(); |
| 186 | if (elf_file.zigObjectPtr()) |zig_object| { | 195 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 187 | try zig_object.addAtomsToRelaSections(elf_file); | 196 | try zig_object.addAtomsToRelaSections(elf_file); |
| ... | @@ -191,6 +200,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const | ... | @@ -191,6 +200,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 191 | try object.addAtomsToOutputSections(elf_file); | 200 | try object.addAtomsToOutputSections(elf_file); |
| 192 | try object.addAtomsToRelaSections(elf_file); | 201 | try object.addAtomsToRelaSections(elf_file); |
| 193 | } | 202 | } |
| 203 | try elf_file.updateMergeSectionSizes(); | ||
| 194 | try updateSectionSizes(elf_file); | 204 | try updateSectionSizes(elf_file); |
| 195 | 205 | ||
| 196 | try allocateAllocSections(elf_file); | 206 | try allocateAllocSections(elf_file); |
| ... | @@ -201,6 +211,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const | ... | @@ -201,6 +211,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 201 | } | 211 | } |
| 202 | 212 | ||
| 203 | try writeAtoms(elf_file); | 213 | try writeAtoms(elf_file); |
| 214 | try elf_file.writeMergeSections(); | ||
| 204 | try writeSyntheticSections(elf_file); | 215 | try writeSyntheticSections(elf_file); |
| 205 | try elf_file.writeShdrTable(); | 216 | try elf_file.writeShdrTable(); |
| 206 | try elf_file.writeElfHeader(); | 217 | try elf_file.writeElfHeader(); |
| ... | @@ -328,7 +339,7 @@ fn updateSectionSizes(elf_file: *Elf) !void { | ... | @@ -328,7 +339,7 @@ fn updateSectionSizes(elf_file: *Elf) !void { |
| 328 | if (!atom_ptr.flags.alive) continue; | 339 | if (!atom_ptr.flags.alive) continue; |
| 329 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | 340 | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 330 | const padding = offset - shdr.sh_size; | 341 | const padding = offset - shdr.sh_size; |
| 331 | atom_ptr.value = offset; | 342 | atom_ptr.value = @intCast(offset); |
| 332 | shdr.sh_size += padding + atom_ptr.size; | 343 | shdr.sh_size += padding + atom_ptr.size; |
| 333 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); | 344 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); |
| 334 | } | 345 | } |
| ... | @@ -434,7 +445,7 @@ fn writeAtoms(elf_file: *Elf) !void { | ... | @@ -434,7 +445,7 @@ fn writeAtoms(elf_file: *Elf) !void { |
| 434 | const atom_ptr = elf_file.atom(atom_index).?; | 445 | const atom_ptr = elf_file.atom(atom_index).?; |
| 435 | assert(atom_ptr.flags.alive); | 446 | assert(atom_ptr.flags.alive); |
| 436 | 447 | ||
| 437 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse | 448 | const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse |
| 438 | return error.Overflow; | 449 | return error.Overflow; |
| 439 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 450 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 440 | 451 |
src/link/Elf/synthetic_sections.zig+47-85| ... | @@ -259,11 +259,7 @@ pub const ZigGotSection = struct { | ... | @@ -259,11 +259,7 @@ pub const ZigGotSection = struct { |
| 259 | if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { | 259 | if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { |
| 260 | zig_got.flags.needs_rela = true; | 260 | zig_got.flags.needs_rela = true; |
| 261 | } | 261 | } |
| 262 | if (symbol.extra(elf_file)) |extra| { | 262 | try symbol.addExtra(.{ .zig_got = index }, elf_file); |
| 263 | var new_extra = extra; | ||
| 264 | new_extra.zig_got = index; | ||
| 265 | symbol.setExtra(new_extra, elf_file); | ||
| 266 | } else try symbol.addExtra(.{ .zig_got = index }, elf_file); | ||
| 267 | return index; | 263 | return index; |
| 268 | } | 264 | } |
| 269 | 265 | ||
| ... | @@ -274,11 +270,11 @@ pub const ZigGotSection = struct { | ... | @@ -274,11 +270,11 @@ pub const ZigGotSection = struct { |
| 274 | return shdr.sh_offset + @as(u64, entry_size) * index; | 270 | return shdr.sh_offset + @as(u64, entry_size) * index; |
| 275 | } | 271 | } |
| 276 | 272 | ||
| 277 | pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 { | 273 | pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 { |
| 278 | _ = zig_got; | 274 | _ = zig_got; |
| 279 | const entry_size = elf_file.archPtrWidthBytes(); | 275 | const entry_size = elf_file.archPtrWidthBytes(); |
| 280 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; | 276 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; |
| 281 | return shdr.sh_addr + @as(u64, entry_size) * index; | 277 | return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index; |
| 282 | } | 278 | } |
| 283 | 279 | ||
| 284 | pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize { | 280 | pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize { |
| ... | @@ -295,23 +291,23 @@ pub const ZigGotSection = struct { | ... | @@ -295,23 +291,23 @@ pub const ZigGotSection = struct { |
| 295 | const target = elf_file.getTarget(); | 291 | const target = elf_file.getTarget(); |
| 296 | const endian = target.cpu.arch.endian(); | 292 | const endian = target.cpu.arch.endian(); |
| 297 | const off = zig_got.entryOffset(index, elf_file); | 293 | const off = zig_got.entryOffset(index, elf_file); |
| 298 | const vaddr = zig_got.entryAddress(index, elf_file); | 294 | const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file)); |
| 299 | const entry = zig_got.entries.items[index]; | 295 | const entry = zig_got.entries.items[index]; |
| 300 | const value = elf_file.symbol(entry).address(.{}, elf_file); | 296 | const value = elf_file.symbol(entry).address(.{}, elf_file); |
| 301 | switch (entry_size) { | 297 | switch (entry_size) { |
| 302 | 2 => { | 298 | 2 => { |
| 303 | var buf: [2]u8 = undefined; | 299 | var buf: [2]u8 = undefined; |
| 304 | std.mem.writeInt(u16, &buf, @as(u16, @intCast(value)), endian); | 300 | std.mem.writeInt(u16, &buf, @intCast(value), endian); |
| 305 | try elf_file.base.file.?.pwriteAll(&buf, off); | 301 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 306 | }, | 302 | }, |
| 307 | 4 => { | 303 | 4 => { |
| 308 | var buf: [4]u8 = undefined; | 304 | var buf: [4]u8 = undefined; |
| 309 | std.mem.writeInt(u32, &buf, @as(u32, @intCast(value)), endian); | 305 | std.mem.writeInt(u32, &buf, @intCast(value), endian); |
| 310 | try elf_file.base.file.?.pwriteAll(&buf, off); | 306 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 311 | }, | 307 | }, |
| 312 | 8 => { | 308 | 8 => { |
| 313 | var buf: [8]u8 = undefined; | 309 | var buf: [8]u8 = undefined; |
| 314 | std.mem.writeInt(u64, &buf, value, endian); | 310 | std.mem.writeInt(u64, &buf, @intCast(value), endian); |
| 315 | try elf_file.base.file.?.pwriteAll(&buf, off); | 311 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 316 | 312 | ||
| 317 | if (elf_file.base.child_pid) |pid| { | 313 | if (elf_file.base.child_pid) |pid| { |
| ... | @@ -360,9 +356,9 @@ pub const ZigGotSection = struct { | ... | @@ -360,9 +356,9 @@ pub const ZigGotSection = struct { |
| 360 | const symbol = elf_file.symbol(entry); | 356 | const symbol = elf_file.symbol(entry); |
| 361 | const offset = symbol.zigGotAddress(elf_file); | 357 | const offset = symbol.zigGotAddress(elf_file); |
| 362 | elf_file.addRelaDynAssumeCapacity(.{ | 358 | elf_file.addRelaDynAssumeCapacity(.{ |
| 363 | .offset = offset, | 359 | .offset = @intCast(offset), |
| 364 | .type = relocation.encode(.rel, cpu_arch), | 360 | .type = relocation.encode(.rel, cpu_arch), |
| 365 | .addend = @intCast(symbol.address(.{ .plt = false }, elf_file)), | 361 | .addend = symbol.address(.{ .plt = false }, elf_file), |
| 366 | }); | 362 | }); |
| 367 | } | 363 | } |
| 368 | } | 364 | } |
| ... | @@ -390,7 +386,7 @@ pub const ZigGotSection = struct { | ... | @@ -390,7 +386,7 @@ pub const ZigGotSection = struct { |
| 390 | .st_info = elf.STT_OBJECT, | 386 | .st_info = elf.STT_OBJECT, |
| 391 | .st_other = 0, | 387 | .st_other = 0, |
| 392 | .st_shndx = @intCast(elf_file.zig_got_section_index.?), | 388 | .st_shndx = @intCast(elf_file.zig_got_section_index.?), |
| 393 | .st_value = st_value, | 389 | .st_value = @intCast(st_value), |
| 394 | .st_size = st_size, | 390 | .st_size = st_size, |
| 395 | }; | 391 | }; |
| 396 | } | 392 | } |
| ... | @@ -461,10 +457,10 @@ pub const GotSection = struct { | ... | @@ -461,10 +457,10 @@ pub const GotSection = struct { |
| 461 | }; | 457 | }; |
| 462 | } | 458 | } |
| 463 | 459 | ||
| 464 | pub fn address(entry: Entry, elf_file: *Elf) u64 { | 460 | pub fn address(entry: Entry, elf_file: *Elf) i64 { |
| 465 | const ptr_bytes = @as(u64, elf_file.archPtrWidthBytes()); | 461 | const ptr_bytes = elf_file.archPtrWidthBytes(); |
| 466 | const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?]; | 462 | const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?]; |
| 467 | return shdr.sh_addr + @as(u64, entry.cell_index) * ptr_bytes; | 463 | return @as(i64, @intCast(shdr.sh_addr)) + entry.cell_index * ptr_bytes; |
| 468 | } | 464 | } |
| 469 | }; | 465 | }; |
| 470 | 466 | ||
| ... | @@ -499,11 +495,7 @@ pub const GotSection = struct { | ... | @@ -499,11 +495,7 @@ pub const GotSection = struct { |
| 499 | { | 495 | { |
| 500 | got.flags.needs_rela = true; | 496 | got.flags.needs_rela = true; |
| 501 | } | 497 | } |
| 502 | if (symbol.extra(elf_file)) |extra| { | 498 | try symbol.addExtra(.{ .got = index }, elf_file); |
| 503 | var new_extra = extra; | ||
| 504 | new_extra.got = index; | ||
| 505 | symbol.setExtra(new_extra, elf_file); | ||
| 506 | } else try symbol.addExtra(.{ .got = index }, elf_file); | ||
| 507 | return index; | 499 | return index; |
| 508 | } | 500 | } |
| 509 | 501 | ||
| ... | @@ -529,11 +521,7 @@ pub const GotSection = struct { | ... | @@ -529,11 +521,7 @@ pub const GotSection = struct { |
| 529 | const symbol = elf_file.symbol(sym_index); | 521 | const symbol = elf_file.symbol(sym_index); |
| 530 | symbol.flags.has_tlsgd = true; | 522 | symbol.flags.has_tlsgd = true; |
| 531 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; | 523 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; |
| 532 | if (symbol.extra(elf_file)) |extra| { | 524 | try symbol.addExtra(.{ .tlsgd = index }, elf_file); |
| 533 | var new_extra = extra; | ||
| 534 | new_extra.tlsgd = index; | ||
| 535 | symbol.setExtra(new_extra, elf_file); | ||
| 536 | } else try symbol.addExtra(.{ .tlsgd = index }, elf_file); | ||
| 537 | } | 525 | } |
| 538 | 526 | ||
| 539 | pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | 527 | pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| ... | @@ -546,11 +534,7 @@ pub const GotSection = struct { | ... | @@ -546,11 +534,7 @@ pub const GotSection = struct { |
| 546 | const symbol = elf_file.symbol(sym_index); | 534 | const symbol = elf_file.symbol(sym_index); |
| 547 | symbol.flags.has_gottp = true; | 535 | symbol.flags.has_gottp = true; |
| 548 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; | 536 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; |
| 549 | if (symbol.extra(elf_file)) |extra| { | 537 | try symbol.addExtra(.{ .gottp = index }, elf_file); |
| 550 | var new_extra = extra; | ||
| 551 | new_extra.gottp = index; | ||
| 552 | symbol.setExtra(new_extra, elf_file); | ||
| 553 | } else try symbol.addExtra(.{ .gottp = index }, elf_file); | ||
| 554 | } | 538 | } |
| 555 | 539 | ||
| 556 | pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | 540 | pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| ... | @@ -563,11 +547,7 @@ pub const GotSection = struct { | ... | @@ -563,11 +547,7 @@ pub const GotSection = struct { |
| 563 | const symbol = elf_file.symbol(sym_index); | 547 | const symbol = elf_file.symbol(sym_index); |
| 564 | symbol.flags.has_tlsdesc = true; | 548 | symbol.flags.has_tlsdesc = true; |
| 565 | got.flags.needs_rela = true; | 549 | got.flags.needs_rela = true; |
| 566 | if (symbol.extra(elf_file)) |extra| { | 550 | try symbol.addExtra(.{ .tlsdesc = index }, elf_file); |
| 567 | var new_extra = extra; | ||
| 568 | new_extra.tlsdesc = index; | ||
| 569 | symbol.setExtra(new_extra, elf_file); | ||
| 570 | } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file); | ||
| 571 | } | 551 | } |
| 572 | 552 | ||
| 573 | pub fn size(got: GotSection, elf_file: *Elf) usize { | 553 | pub fn size(got: GotSection, elf_file: *Elf) usize { |
| ... | @@ -628,8 +608,7 @@ pub const GotSection = struct { | ... | @@ -628,8 +608,7 @@ pub const GotSection = struct { |
| 628 | 0; | 608 | 0; |
| 629 | try writeInt(offset, elf_file, writer); | 609 | try writeInt(offset, elf_file, writer); |
| 630 | } else { | 610 | } else { |
| 631 | const offset = @as(i64, @intCast(symbol.?.address(.{}, elf_file))) - | 611 | const offset = symbol.?.address(.{}, elf_file) - elf_file.tpAddress(); |
| 632 | @as(i64, @intCast(elf_file.tpAddress())); | ||
| 633 | try writeInt(offset, elf_file, writer); | 612 | try writeInt(offset, elf_file, writer); |
| 634 | } | 613 | } |
| 635 | }, | 614 | }, |
| ... | @@ -640,7 +619,7 @@ pub const GotSection = struct { | ... | @@ -640,7 +619,7 @@ pub const GotSection = struct { |
| 640 | } else { | 619 | } else { |
| 641 | try writeInt(0, elf_file, writer); | 620 | try writeInt(0, elf_file, writer); |
| 642 | const offset = if (apply_relocs) | 621 | const offset = if (apply_relocs) |
| 643 | @as(i64, @intCast(symbol.?.address(.{}, elf_file))) - @as(i64, @intCast(elf_file.tlsAddress())) | 622 | symbol.?.address(.{}, elf_file) - elf_file.tlsAddress() |
| 644 | else | 623 | else |
| 645 | 0; | 624 | 0; |
| 646 | try writeInt(offset, elf_file, writer); | 625 | try writeInt(offset, elf_file, writer); |
| ... | @@ -666,7 +645,7 @@ pub const GotSection = struct { | ... | @@ -666,7 +645,7 @@ pub const GotSection = struct { |
| 666 | 645 | ||
| 667 | switch (entry.tag) { | 646 | switch (entry.tag) { |
| 668 | .got => { | 647 | .got => { |
| 669 | const offset = symbol.?.gotAddress(elf_file); | 648 | const offset: u64 = @intCast(symbol.?.gotAddress(elf_file)); |
| 670 | if (symbol.?.flags.import) { | 649 | if (symbol.?.flags.import) { |
| 671 | elf_file.addRelaDynAssumeCapacity(.{ | 650 | elf_file.addRelaDynAssumeCapacity(.{ |
| 672 | .offset = offset, | 651 | .offset = offset, |
| ... | @@ -679,7 +658,7 @@ pub const GotSection = struct { | ... | @@ -679,7 +658,7 @@ pub const GotSection = struct { |
| 679 | elf_file.addRelaDynAssumeCapacity(.{ | 658 | elf_file.addRelaDynAssumeCapacity(.{ |
| 680 | .offset = offset, | 659 | .offset = offset, |
| 681 | .type = relocation.encode(.irel, cpu_arch), | 660 | .type = relocation.encode(.irel, cpu_arch), |
| 682 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | 661 | .addend = symbol.?.address(.{ .plt = false }, elf_file), |
| 683 | }); | 662 | }); |
| 684 | continue; | 663 | continue; |
| 685 | } | 664 | } |
| ... | @@ -689,14 +668,14 @@ pub const GotSection = struct { | ... | @@ -689,14 +668,14 @@ pub const GotSection = struct { |
| 689 | elf_file.addRelaDynAssumeCapacity(.{ | 668 | elf_file.addRelaDynAssumeCapacity(.{ |
| 690 | .offset = offset, | 669 | .offset = offset, |
| 691 | .type = relocation.encode(.rel, cpu_arch), | 670 | .type = relocation.encode(.rel, cpu_arch), |
| 692 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | 671 | .addend = symbol.?.address(.{ .plt = false }, elf_file), |
| 693 | }); | 672 | }); |
| 694 | } | 673 | } |
| 695 | }, | 674 | }, |
| 696 | 675 | ||
| 697 | .tlsld => { | 676 | .tlsld => { |
| 698 | if (is_dyn_lib) { | 677 | if (is_dyn_lib) { |
| 699 | const offset = entry.address(elf_file); | 678 | const offset: u64 = @intCast(entry.address(elf_file)); |
| 700 | elf_file.addRelaDynAssumeCapacity(.{ | 679 | elf_file.addRelaDynAssumeCapacity(.{ |
| 701 | .offset = offset, | 680 | .offset = offset, |
| 702 | .type = relocation.encode(.dtpmod, cpu_arch), | 681 | .type = relocation.encode(.dtpmod, cpu_arch), |
| ... | @@ -705,7 +684,7 @@ pub const GotSection = struct { | ... | @@ -705,7 +684,7 @@ pub const GotSection = struct { |
| 705 | }, | 684 | }, |
| 706 | 685 | ||
| 707 | .tlsgd => { | 686 | .tlsgd => { |
| 708 | const offset = symbol.?.tlsGdAddress(elf_file); | 687 | const offset: u64 = @intCast(symbol.?.tlsGdAddress(elf_file)); |
| 709 | if (symbol.?.flags.import) { | 688 | if (symbol.?.flags.import) { |
| 710 | elf_file.addRelaDynAssumeCapacity(.{ | 689 | elf_file.addRelaDynAssumeCapacity(.{ |
| 711 | .offset = offset, | 690 | .offset = offset, |
| ... | @@ -727,7 +706,7 @@ pub const GotSection = struct { | ... | @@ -727,7 +706,7 @@ pub const GotSection = struct { |
| 727 | }, | 706 | }, |
| 728 | 707 | ||
| 729 | .gottp => { | 708 | .gottp => { |
| 730 | const offset = symbol.?.gotTpAddress(elf_file); | 709 | const offset: u64 = @intCast(symbol.?.gotTpAddress(elf_file)); |
| 731 | if (symbol.?.flags.import) { | 710 | if (symbol.?.flags.import) { |
| 732 | elf_file.addRelaDynAssumeCapacity(.{ | 711 | elf_file.addRelaDynAssumeCapacity(.{ |
| 733 | .offset = offset, | 712 | .offset = offset, |
| ... | @@ -738,18 +717,18 @@ pub const GotSection = struct { | ... | @@ -738,18 +717,18 @@ pub const GotSection = struct { |
| 738 | elf_file.addRelaDynAssumeCapacity(.{ | 717 | elf_file.addRelaDynAssumeCapacity(.{ |
| 739 | .offset = offset, | 718 | .offset = offset, |
| 740 | .type = relocation.encode(.tpoff, cpu_arch), | 719 | .type = relocation.encode(.tpoff, cpu_arch), |
| 741 | .addend = @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), | 720 | .addend = symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(), |
| 742 | }); | 721 | }); |
| 743 | } | 722 | } |
| 744 | }, | 723 | }, |
| 745 | 724 | ||
| 746 | .tlsdesc => { | 725 | .tlsdesc => { |
| 747 | const offset = symbol.?.tlsDescAddress(elf_file); | 726 | const offset: u64 = @intCast(symbol.?.tlsDescAddress(elf_file)); |
| 748 | elf_file.addRelaDynAssumeCapacity(.{ | 727 | elf_file.addRelaDynAssumeCapacity(.{ |
| 749 | .offset = offset, | 728 | .offset = offset, |
| 750 | .sym = if (symbol.?.flags.import) extra.?.dynamic else 0, | 729 | .sym = if (symbol.?.flags.import) extra.?.dynamic else 0, |
| 751 | .type = relocation.encode(.tlsdesc, cpu_arch), | 730 | .type = relocation.encode(.tlsdesc, cpu_arch), |
| 752 | .addend = if (symbol.?.flags.import) 0 else @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), | 731 | .addend = if (symbol.?.flags.import) 0 else symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(), |
| 753 | }); | 732 | }); |
| 754 | }, | 733 | }, |
| 755 | } | 734 | } |
| ... | @@ -826,7 +805,7 @@ pub const GotSection = struct { | ... | @@ -826,7 +805,7 @@ pub const GotSection = struct { |
| 826 | .st_info = elf.STT_OBJECT, | 805 | .st_info = elf.STT_OBJECT, |
| 827 | .st_other = 0, | 806 | .st_other = 0, |
| 828 | .st_shndx = @intCast(elf_file.got_section_index.?), | 807 | .st_shndx = @intCast(elf_file.got_section_index.?), |
| 829 | .st_value = st_value, | 808 | .st_value = @intCast(st_value), |
| 830 | .st_size = st_size, | 809 | .st_size = st_size, |
| 831 | }; | 810 | }; |
| 832 | } | 811 | } |
| ... | @@ -877,11 +856,7 @@ pub const PltSection = struct { | ... | @@ -877,11 +856,7 @@ pub const PltSection = struct { |
| 877 | const index = @as(u32, @intCast(plt.symbols.items.len)); | 856 | const index = @as(u32, @intCast(plt.symbols.items.len)); |
| 878 | const symbol = elf_file.symbol(sym_index); | 857 | const symbol = elf_file.symbol(sym_index); |
| 879 | symbol.flags.has_plt = true; | 858 | symbol.flags.has_plt = true; |
| 880 | if (symbol.extra(elf_file)) |extra| { | 859 | try symbol.addExtra(.{ .plt = index }, elf_file); |
| 881 | var new_extra = extra; | ||
| 882 | new_extra.plt = index; | ||
| 883 | symbol.setExtra(new_extra, elf_file); | ||
| 884 | } else try symbol.addExtra(.{ .plt = index }, elf_file); | ||
| 885 | try plt.symbols.append(gpa, sym_index); | 860 | try plt.symbols.append(gpa, sym_index); |
| 886 | } | 861 | } |
| 887 | 862 | ||
| ... | @@ -924,7 +899,7 @@ pub const PltSection = struct { | ... | @@ -924,7 +899,7 @@ pub const PltSection = struct { |
| 924 | const sym = elf_file.symbol(sym_index); | 899 | const sym = elf_file.symbol(sym_index); |
| 925 | assert(sym.flags.import); | 900 | assert(sym.flags.import); |
| 926 | const extra = sym.extra(elf_file).?; | 901 | const extra = sym.extra(elf_file).?; |
| 927 | const r_offset = sym.gotPltAddress(elf_file); | 902 | const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file)); |
| 928 | const r_sym: u64 = extra.dynamic; | 903 | const r_sym: u64 = extra.dynamic; |
| 929 | const r_type = relocation.encode(.jump_slot, cpu_arch); | 904 | const r_type = relocation.encode(.jump_slot, cpu_arch); |
| 930 | elf_file.rela_plt.appendAssumeCapacity(.{ | 905 | elf_file.rela_plt.appendAssumeCapacity(.{ |
| ... | @@ -960,7 +935,7 @@ pub const PltSection = struct { | ... | @@ -960,7 +935,7 @@ pub const PltSection = struct { |
| 960 | .st_info = elf.STT_FUNC, | 935 | .st_info = elf.STT_FUNC, |
| 961 | .st_other = 0, | 936 | .st_other = 0, |
| 962 | .st_shndx = @intCast(elf_file.plt_section_index.?), | 937 | .st_shndx = @intCast(elf_file.plt_section_index.?), |
| 963 | .st_value = sym.pltAddress(elf_file), | 938 | .st_value = @intCast(sym.pltAddress(elf_file)), |
| 964 | .st_size = entrySize(cpu_arch), | 939 | .st_size = entrySize(cpu_arch), |
| 965 | }; | 940 | }; |
| 966 | } | 941 | } |
| ... | @@ -1033,13 +1008,13 @@ pub const PltSection = struct { | ... | @@ -1033,13 +1008,13 @@ pub const PltSection = struct { |
| 1033 | const aarch64 = struct { | 1008 | const aarch64 = struct { |
| 1034 | fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { | 1009 | fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 1035 | { | 1010 | { |
| 1036 | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; | 1011 | const plt_addr: i64 = @intCast(elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr); |
| 1037 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; | 1012 | const got_plt_addr: i64 = @intCast(elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr); |
| 1038 | // TODO: relax if possible | 1013 | // TODO: relax if possible |
| 1039 | // .got.plt[2] | 1014 | // .got.plt[2] |
| 1040 | const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); | 1015 | const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); |
| 1041 | const ldr_off = try math.divExact(u12, @truncate(got_plt_addr + 16), 8); | 1016 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8); |
| 1042 | const add_off: u12 = @truncate(got_plt_addr + 16); | 1017 | const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); |
| 1043 | 1018 | ||
| 1044 | const preamble = &[_]Instruction{ | 1019 | const preamble = &[_]Instruction{ |
| 1045 | Instruction.stp( | 1020 | Instruction.stp( |
| ... | @@ -1067,8 +1042,8 @@ pub const PltSection = struct { | ... | @@ -1067,8 +1042,8 @@ pub const PltSection = struct { |
| 1067 | const target_addr = sym.gotPltAddress(elf_file); | 1042 | const target_addr = sym.gotPltAddress(elf_file); |
| 1068 | const source_addr = sym.pltAddress(elf_file); | 1043 | const source_addr = sym.pltAddress(elf_file); |
| 1069 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); | 1044 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); |
| 1070 | const ldr_off = try math.divExact(u12, @truncate(target_addr), 8); | 1045 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); |
| 1071 | const add_off: u12 = @truncate(target_addr); | 1046 | const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); |
| 1072 | const insts = &[_]Instruction{ | 1047 | const insts = &[_]Instruction{ |
| 1073 | Instruction.adrp(.x16, pages), | 1048 | Instruction.adrp(.x16, pages), |
| 1074 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), | 1049 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), |
| ... | @@ -1101,7 +1076,7 @@ pub const GotPltSection = struct { | ... | @@ -1101,7 +1076,7 @@ pub const GotPltSection = struct { |
| 1101 | { | 1076 | { |
| 1102 | // [0]: _DYNAMIC | 1077 | // [0]: _DYNAMIC |
| 1103 | const symbol = elf_file.symbol(elf_file.dynamic_index.?); | 1078 | const symbol = elf_file.symbol(elf_file.dynamic_index.?); |
| 1104 | try writer.writeInt(u64, symbol.address(.{}, elf_file), .little); | 1079 | try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); |
| 1105 | } | 1080 | } |
| 1106 | // [1]: 0x0 | 1081 | // [1]: 0x0 |
| 1107 | // [2]: 0x0 | 1082 | // [2]: 0x0 |
| ... | @@ -1132,11 +1107,7 @@ pub const PltGotSection = struct { | ... | @@ -1132,11 +1107,7 @@ pub const PltGotSection = struct { |
| 1132 | const symbol = elf_file.symbol(sym_index); | 1107 | const symbol = elf_file.symbol(sym_index); |
| 1133 | symbol.flags.has_plt = true; | 1108 | symbol.flags.has_plt = true; |
| 1134 | symbol.flags.has_got = true; | 1109 | symbol.flags.has_got = true; |
| 1135 | if (symbol.extra(elf_file)) |extra| { | 1110 | try symbol.addExtra(.{ .plt_got = index }, elf_file); |
| 1136 | var new_extra = extra; | ||
| 1137 | new_extra.plt_got = index; | ||
| 1138 | symbol.setExtra(new_extra, elf_file); | ||
| 1139 | } else try symbol.addExtra(.{ .plt_got = index }, elf_file); | ||
| 1140 | try plt_got.symbols.append(gpa, sym_index); | 1111 | try plt_got.symbols.append(gpa, sym_index); |
| 1141 | } | 1112 | } |
| 1142 | 1113 | ||
| ... | @@ -1181,7 +1152,7 @@ pub const PltGotSection = struct { | ... | @@ -1181,7 +1152,7 @@ pub const PltGotSection = struct { |
| 1181 | .st_info = elf.STT_FUNC, | 1152 | .st_info = elf.STT_FUNC, |
| 1182 | .st_other = 0, | 1153 | .st_other = 0, |
| 1183 | .st_shndx = @intCast(elf_file.plt_got_section_index.?), | 1154 | .st_shndx = @intCast(elf_file.plt_got_section_index.?), |
| 1184 | .st_value = sym.pltGotAddress(elf_file), | 1155 | .st_value = @intCast(sym.pltGotAddress(elf_file)), |
| 1185 | .st_size = 16, | 1156 | .st_size = 16, |
| 1186 | }; | 1157 | }; |
| 1187 | } | 1158 | } |
| ... | @@ -1212,7 +1183,7 @@ pub const PltGotSection = struct { | ... | @@ -1212,7 +1183,7 @@ pub const PltGotSection = struct { |
| 1212 | const target_addr = sym.gotAddress(elf_file); | 1183 | const target_addr = sym.gotAddress(elf_file); |
| 1213 | const source_addr = sym.pltGotAddress(elf_file); | 1184 | const source_addr = sym.pltGotAddress(elf_file); |
| 1214 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); | 1185 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); |
| 1215 | const off = try math.divExact(u12, @truncate(target_addr), 8); | 1186 | const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); |
| 1216 | const insts = &[_]Instruction{ | 1187 | const insts = &[_]Instruction{ |
| 1217 | Instruction.adrp(.x16, pages), | 1188 | Instruction.adrp(.x16, pages), |
| 1218 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), | 1189 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), |
| ... | @@ -1248,12 +1219,7 @@ pub const CopyRelSection = struct { | ... | @@ -1248,12 +1219,7 @@ pub const CopyRelSection = struct { |
| 1248 | symbol.flags.@"export" = true; | 1219 | symbol.flags.@"export" = true; |
| 1249 | symbol.flags.has_copy_rel = true; | 1220 | symbol.flags.has_copy_rel = true; |
| 1250 | symbol.flags.weak = false; | 1221 | symbol.flags.weak = false; |
| 1251 | 1222 | try symbol.addExtra(.{ .copy_rel = index }, elf_file); | |
| 1252 | if (symbol.extra(elf_file)) |extra| { | ||
| 1253 | var new_extra = extra; | ||
| 1254 | new_extra.copy_rel = index; | ||
| 1255 | symbol.setExtra(new_extra, elf_file); | ||
| 1256 | } else try symbol.addExtra(.{ .copy_rel = index }, elf_file); | ||
| 1257 | try copy_rel.symbols.append(gpa, sym_index); | 1223 | try copy_rel.symbols.append(gpa, sym_index); |
| 1258 | 1224 | ||
| 1259 | const shared_object = symbol.file(elf_file).?.shared_object; | 1225 | const shared_object = symbol.file(elf_file).?.shared_object; |
| ... | @@ -1280,9 +1246,9 @@ pub const CopyRelSection = struct { | ... | @@ -1280,9 +1246,9 @@ pub const CopyRelSection = struct { |
| 1280 | const symbol = elf_file.symbol(sym_index); | 1246 | const symbol = elf_file.symbol(sym_index); |
| 1281 | const shared_object = symbol.file(elf_file).?.shared_object; | 1247 | const shared_object = symbol.file(elf_file).?.shared_object; |
| 1282 | const alignment = try symbol.dsoAlignment(elf_file); | 1248 | const alignment = try symbol.dsoAlignment(elf_file); |
| 1283 | symbol.value = mem.alignForward(u64, shdr.sh_size, alignment); | 1249 | symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment)); |
| 1284 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment); | 1250 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment); |
| 1285 | shdr.sh_size = symbol.value + symbol.elfSym(elf_file).st_size; | 1251 | shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size; |
| 1286 | 1252 | ||
| 1287 | const aliases = shared_object.symbolAliases(sym_index, elf_file); | 1253 | const aliases = shared_object.symbolAliases(sym_index, elf_file); |
| 1288 | for (aliases) |alias| { | 1254 | for (aliases) |alias| { |
| ... | @@ -1303,7 +1269,7 @@ pub const CopyRelSection = struct { | ... | @@ -1303,7 +1269,7 @@ pub const CopyRelSection = struct { |
| 1303 | assert(sym.flags.import and sym.flags.has_copy_rel); | 1269 | assert(sym.flags.import and sym.flags.has_copy_rel); |
| 1304 | const extra = sym.extra(elf_file).?; | 1270 | const extra = sym.extra(elf_file).?; |
| 1305 | elf_file.addRelaDynAssumeCapacity(.{ | 1271 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1306 | .offset = sym.address(.{}, elf_file), | 1272 | .offset = @intCast(sym.address(.{}, elf_file)), |
| 1307 | .sym = extra.dynamic, | 1273 | .sym = extra.dynamic, |
| 1308 | .type = relocation.encode(.copy, cpu_arch), | 1274 | .type = relocation.encode(.copy, cpu_arch), |
| 1309 | }); | 1275 | }); |
| ... | @@ -1335,11 +1301,7 @@ pub const DynsymSection = struct { | ... | @@ -1335,11 +1301,7 @@ pub const DynsymSection = struct { |
| 1335 | const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); | 1301 | const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); |
| 1336 | const sym = elf_file.symbol(sym_index); | 1302 | const sym = elf_file.symbol(sym_index); |
| 1337 | sym.flags.has_dynamic = true; | 1303 | sym.flags.has_dynamic = true; |
| 1338 | if (sym.extra(elf_file)) |extra| { | 1304 | try sym.addExtra(.{ .dynamic = index }, elf_file); |
| 1339 | var new_extra = extra; | ||
| 1340 | new_extra.dynamic = index; | ||
| 1341 | sym.setExtra(new_extra, elf_file); | ||
| 1342 | } else try sym.addExtra(.{ .dynamic = index }, elf_file); | ||
| 1343 | const off = try elf_file.insertDynString(sym.name(elf_file)); | 1305 | const off = try elf_file.insertDynString(sym.name(elf_file)); |
| 1344 | try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off }); | 1306 | try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off }); |
| 1345 | } | 1307 | } |
src/link/Elf/thunks.zig+18-16| ... | @@ -7,7 +7,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { | ... | @@ -7,7 +7,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { |
| 7 | assert(atoms.len > 0); | 7 | assert(atoms.len > 0); |
| 8 | 8 | ||
| 9 | for (atoms) |atom_index| { | 9 | for (atoms) |atom_index| { |
| 10 | elf_file.atom(atom_index).?.value = @bitCast(@as(i64, -1)); | 10 | elf_file.atom(atom_index).?.value = -1; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | var i: usize = 0; | 13 | var i: usize = 0; |
| ... | @@ -22,7 +22,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { | ... | @@ -22,7 +22,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { |
| 22 | const atom_index = atoms[i]; | 22 | const atom_index = atoms[i]; |
| 23 | const atom = elf_file.atom(atom_index).?; | 23 | const atom = elf_file.atom(atom_index).?; |
| 24 | assert(atom.flags.alive); | 24 | assert(atom.flags.alive); |
| 25 | if (atom.alignment.forward(shdr.sh_size) - start_atom.value >= max_distance) break; | 25 | if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance) |
| 26 | break; | ||
| 26 | atom.value = try advance(shdr, atom.size, atom.alignment); | 27 | atom.value = try advance(shdr, atom.size, atom.alignment); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| ... | @@ -50,7 +51,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { | ... | @@ -50,7 +51,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { |
| 50 | }; | 51 | }; |
| 51 | try thunk.symbols.put(gpa, target, {}); | 52 | try thunk.symbols.put(gpa, target, {}); |
| 52 | } | 53 | } |
| 53 | atom.thunk_index = thunk_index; | 54 | try atom.addExtra(.{ .thunk = thunk_index }, elf_file); |
| 55 | atom.flags.thunk = true; | ||
| 54 | } | 56 | } |
| 55 | 57 | ||
| 56 | thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); | 58 | thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); |
| ... | @@ -59,12 +61,12 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { | ... | @@ -59,12 +61,12 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { |
| 59 | } | 61 | } |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 { | 64 | fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !i64 { |
| 63 | const offset = alignment.forward(shdr.sh_size); | 65 | const offset = alignment.forward(shdr.sh_size); |
| 64 | const padding = offset - shdr.sh_size; | 66 | const padding = offset - shdr.sh_size; |
| 65 | shdr.sh_size += padding + size; | 67 | shdr.sh_size += padding + size; |
| 66 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); | 68 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); |
| 67 | return offset; | 69 | return @intCast(offset); |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | /// A branch will need an extender if its target is larger than | 72 | /// A branch will need an extender if its target is larger than |
| ... | @@ -78,7 +80,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { | ... | @@ -78,7 +80,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { |
| 78 | } | 80 | } |
| 79 | 81 | ||
| 80 | pub const Thunk = struct { | 82 | pub const Thunk = struct { |
| 81 | value: u64 = 0, | 83 | value: i64 = 0, |
| 82 | output_section_index: u32 = 0, | 84 | output_section_index: u32 = 0, |
| 83 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | 85 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, |
| 84 | output_symtab_ctx: Elf.SymtabCtx = .{}, | 86 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| ... | @@ -92,14 +94,14 @@ pub const Thunk = struct { | ... | @@ -92,14 +94,14 @@ pub const Thunk = struct { |
| 92 | return thunk.symbols.keys().len * trampolineSize(cpu_arch); | 94 | return thunk.symbols.keys().len * trampolineSize(cpu_arch); |
| 93 | } | 95 | } |
| 94 | 96 | ||
| 95 | pub fn address(thunk: Thunk, elf_file: *Elf) u64 { | 97 | pub fn address(thunk: Thunk, elf_file: *Elf) i64 { |
| 96 | const shdr = elf_file.shdrs.items[thunk.output_section_index]; | 98 | const shdr = elf_file.shdrs.items[thunk.output_section_index]; |
| 97 | return shdr.sh_addr + thunk.value; | 99 | return @as(i64, @intCast(shdr.sh_addr)) + thunk.value; |
| 98 | } | 100 | } |
| 99 | 101 | ||
| 100 | pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) u64 { | 102 | pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 { |
| 101 | const cpu_arch = elf_file.getTarget().cpu.arch; | 103 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 102 | return thunk.address(elf_file) + thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch); | 104 | return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch))); |
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | 107 | pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { |
| ... | @@ -131,7 +133,7 @@ pub const Thunk = struct { | ... | @@ -131,7 +133,7 @@ pub const Thunk = struct { |
| 131 | .st_info = elf.STT_FUNC, | 133 | .st_info = elf.STT_FUNC, |
| 132 | .st_other = 0, | 134 | .st_other = 0, |
| 133 | .st_shndx = @intCast(thunk.output_section_index), | 135 | .st_shndx = @intCast(thunk.output_section_index), |
| 134 | .st_value = thunk.targetAddress(sym_index, elf_file), | 136 | .st_value = @intCast(thunk.targetAddress(sym_index, elf_file)), |
| 135 | .st_size = trampolineSize(cpu_arch), | 137 | .st_size = trampolineSize(cpu_arch), |
| 136 | }; | 138 | }; |
| 137 | } | 139 | } |
| ... | @@ -204,9 +206,9 @@ const aarch64 = struct { | ... | @@ -204,9 +206,9 @@ const aarch64 = struct { |
| 204 | if (target.flags.has_plt) return false; | 206 | if (target.flags.has_plt) return false; |
| 205 | if (atom.output_section_index != target.output_section_index) return false; | 207 | if (atom.output_section_index != target.output_section_index) return false; |
| 206 | const target_atom = target.atom(elf_file).?; | 208 | const target_atom = target.atom(elf_file).?; |
| 207 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | 209 | if (target_atom.value == -1) return false; |
| 208 | const saddr = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset)); | 210 | const saddr = atom.address(elf_file) + @as(i64, @intCast(rel.r_offset)); |
| 209 | const taddr: i64 = @intCast(target.address(.{}, elf_file)); | 211 | const taddr = target.address(.{}, elf_file); |
| 210 | _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false; | 212 | _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false; |
| 211 | return true; | 213 | return true; |
| 212 | } | 214 | } |
| ... | @@ -214,11 +216,11 @@ const aarch64 = struct { | ... | @@ -214,11 +216,11 @@ const aarch64 = struct { |
| 214 | fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | 216 | fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { |
| 215 | for (thunk.symbols.keys(), 0..) |sym_index, i| { | 217 | for (thunk.symbols.keys(), 0..) |sym_index, i| { |
| 216 | const sym = elf_file.symbol(sym_index); | 218 | const sym = elf_file.symbol(sym_index); |
| 217 | const saddr = thunk.address(elf_file) + i * trampoline_size; | 219 | const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); |
| 218 | const taddr = sym.address(.{}, elf_file); | 220 | const taddr = sym.address(.{}, elf_file); |
| 219 | const pages = try util.calcNumberOfPages(saddr, taddr); | 221 | const pages = try util.calcNumberOfPages(saddr, taddr); |
| 220 | try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); | 222 | try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); |
| 221 | const off: u12 = @truncate(taddr); | 223 | const off: u12 = @truncate(@as(u64, @bitCast(taddr))); |
| 222 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); | 224 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); |
| 223 | try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); | 225 | try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); |
| 224 | } | 226 | } |
src/link/MachO/Atom.zig+1-1| ... | @@ -770,7 +770,7 @@ fn resolveRelocInner( | ... | @@ -770,7 +770,7 @@ fn resolveRelocInner( |
| 770 | }; | 770 | }; |
| 771 | break :target math.cast(u64, target) orelse return error.Overflow; | 771 | break :target math.cast(u64, target) orelse return error.Overflow; |
| 772 | }; | 772 | }; |
| 773 | const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(source, target))); | 773 | const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)))); |
| 774 | aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); | 774 | aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); |
| 775 | }, | 775 | }, |
| 776 | 776 |
src/link/MachO/synthetic.zig+5-5| ... | @@ -267,7 +267,7 @@ pub const StubsSection = struct { | ... | @@ -267,7 +267,7 @@ pub const StubsSection = struct { |
| 267 | }, | 267 | }, |
| 268 | .aarch64 => { | 268 | .aarch64 => { |
| 269 | // TODO relax if possible | 269 | // TODO relax if possible |
| 270 | const pages = try aarch64.calcNumberOfPages(source, target); | 270 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 271 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | 271 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 272 | const off = try math.divExact(u12, @truncate(target), 8); | 272 | const off = try math.divExact(u12, @truncate(target), 8); |
| 273 | try writer.writeInt( | 273 | try writer.writeInt( |
| ... | @@ -411,7 +411,7 @@ pub const StubsHelperSection = struct { | ... | @@ -411,7 +411,7 @@ pub const StubsHelperSection = struct { |
| 411 | .aarch64 => { | 411 | .aarch64 => { |
| 412 | { | 412 | { |
| 413 | // TODO relax if possible | 413 | // TODO relax if possible |
| 414 | const pages = try aarch64.calcNumberOfPages(sect.addr, dyld_private_addr); | 414 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr)); |
| 415 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); | 415 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); |
| 416 | const off: u12 = @truncate(dyld_private_addr); | 416 | const off: u12 = @truncate(dyld_private_addr); |
| 417 | try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); | 417 | try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); |
| ... | @@ -424,7 +424,7 @@ pub const StubsHelperSection = struct { | ... | @@ -424,7 +424,7 @@ pub const StubsHelperSection = struct { |
| 424 | ).toU32(), .little); | 424 | ).toU32(), .little); |
| 425 | { | 425 | { |
| 426 | // TODO relax if possible | 426 | // TODO relax if possible |
| 427 | const pages = try aarch64.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr); | 427 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr)); |
| 428 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | 428 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 429 | const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); | 429 | const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); |
| 430 | try writer.writeInt(u32, aarch64.Instruction.ldr( | 430 | try writer.writeInt(u32, aarch64.Instruction.ldr( |
| ... | @@ -679,7 +679,7 @@ pub const ObjcStubsSection = struct { | ... | @@ -679,7 +679,7 @@ pub const ObjcStubsSection = struct { |
| 679 | { | 679 | { |
| 680 | const target = sym.getObjcSelrefsAddress(macho_file); | 680 | const target = sym.getObjcSelrefsAddress(macho_file); |
| 681 | const source = addr; | 681 | const source = addr; |
| 682 | const pages = try aarch64.calcNumberOfPages(source, target); | 682 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 683 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); | 683 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); |
| 684 | const off = try math.divExact(u12, @truncate(target), 8); | 684 | const off = try math.divExact(u12, @truncate(target), 8); |
| 685 | try writer.writeInt( | 685 | try writer.writeInt( |
| ... | @@ -692,7 +692,7 @@ pub const ObjcStubsSection = struct { | ... | @@ -692,7 +692,7 @@ pub const ObjcStubsSection = struct { |
| 692 | const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?); | 692 | const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?); |
| 693 | const target = target_sym.getGotAddress(macho_file); | 693 | const target = target_sym.getGotAddress(macho_file); |
| 694 | const source = addr + 2 * @sizeOf(u32); | 694 | const source = addr + 2 * @sizeOf(u32); |
| 695 | const pages = try aarch64.calcNumberOfPages(source, target); | 695 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 696 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | 696 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 697 | const off = try math.divExact(u12, @truncate(target), 8); | 697 | const off = try math.divExact(u12, @truncate(target), 8); |
| 698 | try writer.writeInt( | 698 | try writer.writeInt( |
src/link/MachO/thunks.zig+1-1| ... | @@ -99,7 +99,7 @@ pub const Thunk = struct { | ... | @@ -99,7 +99,7 @@ pub const Thunk = struct { |
| 99 | const sym = macho_file.getSymbol(sym_index); | 99 | const sym = macho_file.getSymbol(sym_index); |
| 100 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; | 100 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 101 | const taddr = sym.getAddress(.{}, macho_file); | 101 | const taddr = sym.getAddress(.{}, macho_file); |
| 102 | const pages = try aarch64.calcNumberOfPages(saddr, taddr); | 102 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| 103 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | 103 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 104 | const off: u12 = @truncate(taddr); | 104 | const off: u12 = @truncate(taddr); |
| 105 | try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); | 105 | try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); |
src/link/aarch64.zig+1-1| ... | @@ -25,7 +25,7 @@ pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void { | ... | @@ -25,7 +25,7 @@ pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void { |
| 25 | mem.writeInt(u32, code, inst.toU32(), .little); | 25 | mem.writeInt(u32, code, inst.toU32(), .little); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 { | 28 | pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 { |
| 29 | const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; | 29 | const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; |
| 30 | const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; | 30 | const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; |
| 31 | const pages = math.cast(i21, tpage - spage) orelse return error.Overflow; | 31 | const pages = math.cast(i21, tpage - spage) orelse return error.Overflow; |
test/link/elf.zig+182| ... | @@ -61,6 +61,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -61,6 +61,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 61 | elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target })); | 61 | elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target })); |
| 62 | elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target })); | 62 | elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target })); |
| 63 | elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target })); | 63 | elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target })); |
| 64 | elf_step.dependOn(testCommentString(b, .{ .target = musl_target })); | ||
| 64 | elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); | 65 | elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); |
| 65 | elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); | 66 | elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); |
| 66 | elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); | 67 | elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); |
| ... | @@ -72,6 +73,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -72,6 +73,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 72 | elf_step.dependOn(testLinkingC(b, .{ .target = musl_target })); | 73 | elf_step.dependOn(testLinkingC(b, .{ .target = musl_target })); |
| 73 | elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target })); | 74 | elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target })); |
| 74 | elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target })); | 75 | elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target })); |
| 76 | elf_step.dependOn(testMergeStrings(b, .{ .target = musl_target })); | ||
| 77 | elf_step.dependOn(testMergeStrings2(b, .{ .target = musl_target })); | ||
| 75 | // https://github.com/ziglang/zig/issues/17451 | 78 | // https://github.com/ziglang/zig/issues/17451 |
| 76 | // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target })); | 79 | // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target })); |
| 77 | elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target })); | 80 | elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target })); |
| ... | @@ -81,6 +84,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -81,6 +84,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 81 | elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target })); | 84 | elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target })); |
| 82 | // https://github.com/ziglang/zig/issues/17430 | 85 | // https://github.com/ziglang/zig/issues/17430 |
| 83 | // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target })); | 86 | // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target })); |
| 87 | elf_step.dependOn(testCommentString(b, .{ .target = gnu_target })); | ||
| 84 | elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target })); | 88 | elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target })); |
| 85 | // https://github.com/ziglang/zig/issues/17430 | 89 | // https://github.com/ziglang/zig/issues/17430 |
| 86 | // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target })); | 90 | // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target })); |
| ... | @@ -152,6 +156,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -152,6 +156,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 152 | elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl })); | 156 | elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl })); |
| 153 | 157 | ||
| 154 | // x86_64 self-hosted backend | 158 | // x86_64 self-hosted backend |
| 159 | elf_step.dependOn(testCommentString(b, .{ .use_llvm = false, .target = default_target })); | ||
| 160 | elf_step.dependOn(testCommentStringStaticLib(b, .{ .use_llvm = false, .target = default_target })); | ||
| 155 | elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl })); | 161 | elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl })); |
| 156 | elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl })); | 162 | elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl })); |
| 157 | elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target })); | 163 | elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target })); |
| ... | @@ -362,6 +368,36 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step { | ... | @@ -362,6 +368,36 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step { |
| 362 | return test_step; | 368 | return test_step; |
| 363 | } | 369 | } |
| 364 | 370 | ||
| 371 | fn testCommentString(b: *Build, opts: Options) *Step { | ||
| 372 | const test_step = addTestStep(b, "comment-string", opts); | ||
| 373 | |||
| 374 | const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = | ||
| 375 | \\pub fn main() void {} | ||
| 376 | }); | ||
| 377 | |||
| 378 | const check = exe.checkObject(); | ||
| 379 | check.dumpSection(".comment"); | ||
| 380 | check.checkContains("zig"); | ||
| 381 | test_step.dependOn(&check.step); | ||
| 382 | |||
| 383 | return test_step; | ||
| 384 | } | ||
| 385 | |||
| 386 | fn testCommentStringStaticLib(b: *Build, opts: Options) *Step { | ||
| 387 | const test_step = addTestStep(b, "comment-string-static-lib", opts); | ||
| 388 | |||
| 389 | const lib = addStaticLibrary(b, opts, .{ .name = "lib", .zig_source_bytes = | ||
| 390 | \\export fn foo() void {} | ||
| 391 | }); | ||
| 392 | |||
| 393 | const check = lib.checkObject(); | ||
| 394 | check.dumpSection(".comment"); | ||
| 395 | check.checkContains("zig"); | ||
| 396 | test_step.dependOn(&check.step); | ||
| 397 | |||
| 398 | return test_step; | ||
| 399 | } | ||
| 400 | |||
| 365 | fn testCommonSymbols(b: *Build, opts: Options) *Step { | 401 | fn testCommonSymbols(b: *Build, opts: Options) *Step { |
| 366 | const test_step = addTestStep(b, "common-symbols", opts); | 402 | const test_step = addTestStep(b, "common-symbols", opts); |
| 367 | 403 | ||
| ... | @@ -2267,6 +2303,125 @@ fn testLinkingZig(b: *Build, opts: Options) *Step { | ... | @@ -2267,6 +2303,125 @@ fn testLinkingZig(b: *Build, opts: Options) *Step { |
| 2267 | return test_step; | 2303 | return test_step; |
| 2268 | } | 2304 | } |
| 2269 | 2305 | ||
| 2306 | // Adapted from https://github.com/rui314/mold/blob/main/test/elf/mergeable-strings.sh | ||
| 2307 | fn testMergeStrings(b: *Build, opts: Options) *Step { | ||
| 2308 | const test_step = addTestStep(b, "merge-strings", opts); | ||
| 2309 | |||
| 2310 | const obj1 = addObject(b, opts, .{ .name = "a.o" }); | ||
| 2311 | addCSourceBytes(obj1, | ||
| 2312 | \\#include <uchar.h> | ||
| 2313 | \\#include <wchar.h> | ||
| 2314 | \\char *cstr1 = "foo"; | ||
| 2315 | \\wchar_t *wide1 = L"foo"; | ||
| 2316 | \\char16_t *utf16_1 = u"foo"; | ||
| 2317 | \\char32_t *utf32_1 = U"foo"; | ||
| 2318 | , &.{"-O2"}); | ||
| 2319 | obj1.linkLibC(); | ||
| 2320 | |||
| 2321 | const obj2 = addObject(b, opts, .{ .name = "b.o" }); | ||
| 2322 | addCSourceBytes(obj2, | ||
| 2323 | \\#include <stdio.h> | ||
| 2324 | \\#include <assert.h> | ||
| 2325 | \\#include <uchar.h> | ||
| 2326 | \\#include <wchar.h> | ||
| 2327 | \\extern char *cstr1; | ||
| 2328 | \\extern wchar_t *wide1; | ||
| 2329 | \\extern char16_t *utf16_1; | ||
| 2330 | \\extern char32_t *utf32_1; | ||
| 2331 | \\char *cstr2 = "foo"; | ||
| 2332 | \\wchar_t *wide2 = L"foo"; | ||
| 2333 | \\char16_t *utf16_2 = u"foo"; | ||
| 2334 | \\char32_t *utf32_2 = U"foo"; | ||
| 2335 | \\int main() { | ||
| 2336 | \\ printf("%p %p %p %p %p %p %p %p\n", | ||
| 2337 | \\ cstr1, cstr2, wide1, wide2, utf16_1, utf16_2, utf32_1, utf32_2); | ||
| 2338 | \\ assert((void*)cstr1 == (void*)cstr2); | ||
| 2339 | \\ assert((void*)wide1 == (void*)wide2); | ||
| 2340 | \\ assert((void*)utf16_1 == (void*)utf16_2); | ||
| 2341 | \\ assert((void*)utf32_1 == (void*)utf32_2); | ||
| 2342 | \\ assert((void*)wide1 == (void*)utf32_1); | ||
| 2343 | \\ assert((void*)cstr1 != (void*)wide1); | ||
| 2344 | \\ assert((void*)cstr1 != (void*)utf32_1); | ||
| 2345 | \\ assert((void*)wide1 != (void*)utf16_1); | ||
| 2346 | \\} | ||
| 2347 | , &.{"-O2"}); | ||
| 2348 | obj2.linkLibC(); | ||
| 2349 | |||
| 2350 | const exe = addExecutable(b, opts, .{ .name = "main" }); | ||
| 2351 | exe.addObject(obj1); | ||
| 2352 | exe.addObject(obj2); | ||
| 2353 | exe.linkLibC(); | ||
| 2354 | |||
| 2355 | const run = addRunArtifact(exe); | ||
| 2356 | run.expectExitCode(0); | ||
| 2357 | test_step.dependOn(&run.step); | ||
| 2358 | |||
| 2359 | return test_step; | ||
| 2360 | } | ||
| 2361 | |||
| 2362 | fn testMergeStrings2(b: *Build, opts: Options) *Step { | ||
| 2363 | const test_step = addTestStep(b, "merge-strings2", opts); | ||
| 2364 | |||
| 2365 | const obj1 = addObject(b, opts, .{ .name = "a", .zig_source_bytes = | ||
| 2366 | \\const std = @import("std"); | ||
| 2367 | \\export fn foo() void { | ||
| 2368 | \\ var arr: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; | ||
| 2369 | \\ const slice = std.mem.sliceTo(&arr, 3); | ||
| 2370 | \\ std.testing.expectEqualSlices(u16, arr[0..2], slice) catch unreachable; | ||
| 2371 | \\} | ||
| 2372 | }); | ||
| 2373 | |||
| 2374 | const obj2 = addObject(b, opts, .{ .name = "b", .zig_source_bytes = | ||
| 2375 | \\const std = @import("std"); | ||
| 2376 | \\extern fn foo() void; | ||
| 2377 | \\pub fn main() void { | ||
| 2378 | \\ foo(); | ||
| 2379 | \\ var arr: [5:0]u16 = [_:0]u16{ 5, 4, 3, 2, 1 }; | ||
| 2380 | \\ const slice = std.mem.sliceTo(&arr, 3); | ||
| 2381 | \\ std.testing.expectEqualSlices(u16, arr[0..2], slice) catch unreachable; | ||
| 2382 | \\} | ||
| 2383 | }); | ||
| 2384 | |||
| 2385 | { | ||
| 2386 | const exe = addExecutable(b, opts, .{ .name = "main1" }); | ||
| 2387 | exe.addObject(obj1); | ||
| 2388 | exe.addObject(obj2); | ||
| 2389 | |||
| 2390 | const run = addRunArtifact(exe); | ||
| 2391 | run.expectExitCode(0); | ||
| 2392 | test_step.dependOn(&run.step); | ||
| 2393 | |||
| 2394 | const check = exe.checkObject(); | ||
| 2395 | check.dumpSection(".rodata.str"); | ||
| 2396 | check.checkContains("\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x00\x00"); | ||
| 2397 | check.dumpSection(".rodata.str"); | ||
| 2398 | check.checkContains("\x05\x00\x04\x00\x03\x00\x02\x00\x01\x00\x00\x00"); | ||
| 2399 | test_step.dependOn(&check.step); | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | { | ||
| 2403 | const obj3 = addObject(b, opts, .{ .name = "c" }); | ||
| 2404 | obj3.addObject(obj1); | ||
| 2405 | obj3.addObject(obj2); | ||
| 2406 | |||
| 2407 | const exe = addExecutable(b, opts, .{ .name = "main2" }); | ||
| 2408 | exe.addObject(obj3); | ||
| 2409 | |||
| 2410 | const run = addRunArtifact(exe); | ||
| 2411 | run.expectExitCode(0); | ||
| 2412 | test_step.dependOn(&run.step); | ||
| 2413 | |||
| 2414 | const check = exe.checkObject(); | ||
| 2415 | check.dumpSection(".rodata.str"); | ||
| 2416 | check.checkContains("\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x00\x00"); | ||
| 2417 | check.dumpSection(".rodata.str"); | ||
| 2418 | check.checkContains("\x05\x00\x04\x00\x03\x00\x02\x00\x01\x00\x00\x00"); | ||
| 2419 | test_step.dependOn(&check.step); | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | return test_step; | ||
| 2423 | } | ||
| 2424 | |||
| 2270 | fn testNoEhFrameHdr(b: *Build, opts: Options) *Step { | 2425 | fn testNoEhFrameHdr(b: *Build, opts: Options) *Step { |
| 2271 | const test_step = addTestStep(b, "no-eh-frame-hdr", opts); | 2426 | const test_step = addTestStep(b, "no-eh-frame-hdr", opts); |
| 2272 | 2427 | ||
| ... | @@ -2528,6 +2683,33 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { | ... | @@ -2528,6 +2683,33 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { |
| 2528 | return test_step; | 2683 | return test_step; |
| 2529 | } | 2684 | } |
| 2530 | 2685 | ||
| 2686 | // Adapted from https://github.com/rui314/mold/blob/main/test/elf/relocatable-mergeable-sections.sh | ||
| 2687 | fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step { | ||
| 2688 | const test_step = addTestStep(b, "relocatable-merge-strings", opts); | ||
| 2689 | |||
| 2690 | const obj1 = addObject(b, opts, .{ .name = "a", .asm_source_bytes = | ||
| 2691 | \\.section .rodata.str1.1,"aMS",@progbits,1 | ||
| 2692 | \\val1: | ||
| 2693 | \\.ascii "Hello \0" | ||
| 2694 | \\.section .rodata.str1.1,"aMS",@progbits,1 | ||
| 2695 | \\val5: | ||
| 2696 | \\.ascii "World \0" | ||
| 2697 | \\.section .rodata.str1.1,"aMS",@progbits,1 | ||
| 2698 | \\val7: | ||
| 2699 | \\.ascii "Hello \0" | ||
| 2700 | }); | ||
| 2701 | |||
| 2702 | const obj2 = addObject(b, opts, .{ .name = "b" }); | ||
| 2703 | obj2.addObject(obj1); | ||
| 2704 | |||
| 2705 | const check = obj2.checkObject(); | ||
| 2706 | check.dumpSection(".rodata.str1.1"); | ||
| 2707 | check.checkExact("Hello \x00World \x00"); | ||
| 2708 | test_step.dependOn(&check.step); | ||
| 2709 | |||
| 2710 | return test_step; | ||
| 2711 | } | ||
| 2712 | |||
| 2531 | fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step { | 2713 | fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step { |
| 2532 | const test_step = addTestStep(b, "relocatable-no-eh-frame", opts); | 2714 | const test_step = addTestStep(b, "relocatable-no-eh-frame", opts); |
| 2533 | 2715 |
test/link/link.zig-18| ... | @@ -1,21 +1,3 @@ | ... | @@ -1,21 +1,3 @@ |
| 1 | pub fn build(b: *Build) void { | ||
| 2 | const test_step = b.step("test-link", "Run link tests"); | ||
| 3 | b.default_step = test_step; | ||
| 4 | |||
| 5 | const has_macos_sdk = b.option(bool, "has_macos_sdk", "whether the host provides a macOS SDK in system path"); | ||
| 6 | const has_ios_sdk = b.option(bool, "has_ios_sdk", "whether the host provides a iOS SDK in system path"); | ||
| 7 | const has_symlinks_windows = b.option(bool, "has_symlinks_windows", "whether the host is windows and has symlinks enabled"); | ||
| 8 | |||
| 9 | const build_opts: BuildOptions = .{ | ||
| 10 | .has_macos_sdk = has_macos_sdk orelse false, | ||
| 11 | .has_ios_sdk = has_ios_sdk orelse false, | ||
| 12 | .has_symlinks_windows = has_symlinks_windows orelse false, | ||
| 13 | }; | ||
| 14 | |||
| 15 | test_step.dependOn(@import("elf.zig").testAll(b, build_opts)); | ||
| 16 | test_step.dependOn(@import("macho.zig").testAll(b, build_opts)); | ||
| 17 | } | ||
| 18 | |||
| 19 | pub const BuildOptions = struct { | 1 | pub const BuildOptions = struct { |
| 20 | has_macos_sdk: bool, | 2 | has_macos_sdk: bool, |
| 21 | has_ios_sdk: bool, | 3 | has_ios_sdk: bool, |