| author | |
| committer | |
| log | 3c5e840732053318f5e722d6cc16f65d51cdc297 |
| tree | 1e58c6a4837bda9e92c0a3a465b3ea7bc5d0eb0a |
| parent | e0d7a98b72f54aa502ed43cda7c712962489ba54 |
| parent | da55af1cae6065be5313946ec4c9acd465bb04ad |
| signature |
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 | 205 | |
| 206 | 206 | /// List of atoms that are owned directly by the linker. |
| 207 | 207 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 208 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 208 | 209 | |
| 209 | 210 | /// List of range extension thunks. |
| 210 | 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 | 221 | /// Table of last atom index in a section and matching atom free list if any. |
| 213 | 222 | last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, |
| 214 | 223 | |
| ... | ... | @@ -369,6 +378,7 @@ pub fn createEmpty( |
| 369 | 378 | try self.symbols_extra.append(gpa, 0); |
| 370 | 379 | // Allocate atom index 0 to null atom |
| 371 | 380 | try self.atoms.append(gpa, .{}); |
| 381 | try self.atoms_extra.append(gpa, 0); | |
| 372 | 382 | // Append null file at index 0 |
| 373 | 383 | try self.files.append(gpa, .null); |
| 374 | 384 | // Append null byte to string tables |
| ... | ... | @@ -378,6 +388,8 @@ pub fn createEmpty( |
| 378 | 388 | _ = try self.addSection(.{ .name = "" }); |
| 379 | 389 | // Append null symbol in output symtab |
| 380 | 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 | 394 | if (!is_obj_or_ar) { |
| 383 | 395 | try self.dynstrtab.append(gpa, 0); |
| ... | ... | @@ -491,7 +503,20 @@ pub fn deinit(self: *Elf) void { |
| 491 | 503 | self.start_stop_indexes.deinit(gpa); |
| 492 | 504 | |
| 493 | 505 | self.atoms.deinit(gpa); |
| 506 | self.atoms_extra.deinit(gpa); | |
| 507 | for (self.thunks.items) |*th| { | |
| 508 | th.deinit(gpa); | |
| 509 | } | |
| 494 | 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 | 520 | for (self.last_atom_and_free_list_table.values()) |*value| { |
| 496 | 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 | 1314 | // symbol for potential resolution at load-time. |
| 1290 | 1315 | self.resolveSymbols(); |
| 1291 | 1316 | self.markEhFrameAtomsDead(); |
| 1317 | try self.resolveMergeSections(); | |
| 1292 | 1318 | |
| 1293 | 1319 | try self.convertCommonSymbols(); |
| 1294 | 1320 | self.markImportsExports(); |
| ... | ... | @@ -1313,7 +1339,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1313 | 1339 | else => |e| return e, |
| 1314 | 1340 | }; |
| 1315 | 1341 | |
| 1342 | try self.addCommentString(); | |
| 1343 | try self.finalizeMergeSections(); | |
| 1316 | 1344 | try self.initOutputSections(); |
| 1345 | try self.initMergeSections(); | |
| 1317 | 1346 | try self.addLinkerDefinedSymbols(); |
| 1318 | 1347 | self.claimUnresolved(); |
| 1319 | 1348 | |
| ... | ... | @@ -1332,6 +1361,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1332 | 1361 | self.sortDynamicSymtab(); |
| 1333 | 1362 | try self.setHashSections(); |
| 1334 | 1363 | try self.setVersionSymtab(); |
| 1364 | try self.updateMergeSectionSizes(); | |
| 1335 | 1365 | try self.updateSectionSizes(); |
| 1336 | 1366 | |
| 1337 | 1367 | try self.allocatePhdrTable(); |
| ... | ... | @@ -1359,7 +1389,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1359 | 1389 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1360 | 1390 | const code = try zig_object.codeAlloc(self, atom_index); |
| 1361 | 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 | 1393 | atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { |
| 1364 | 1394 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, |
| 1365 | 1395 | error.UnsupportedCpuArch => { |
| ... | ... | @@ -1377,6 +1407,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1377 | 1407 | try self.writePhdrTable(); |
| 1378 | 1408 | try self.writeShdrTable(); |
| 1379 | 1409 | try self.writeAtoms(); |
| 1410 | try self.writeMergeSections(); | |
| 1380 | 1411 | self.writeSyntheticSections() catch |err| switch (err) { |
| 1381 | 1412 | error.RelocFailure => return error.FlushFailure, |
| 1382 | 1413 | error.UnsupportedCpuArch => { |
| ... | ... | @@ -2946,7 +2977,10 @@ pub fn writeElfHeader(self: *Elf) !void { |
| 2946 | 2977 | mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); |
| 2947 | 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 | 2984 | const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0; |
| 2951 | 2985 | switch (self.ptr_width) { |
| 2952 | 2986 | .p32 => { |
| ... | ... | @@ -3132,14 +3166,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3132 | 3166 | if (self.dynamic_section_index) |shndx| { |
| 3133 | 3167 | const shdr = &self.shdrs.items[shndx]; |
| 3134 | 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 | 3170 | symbol_ptr.output_section_index = shndx; |
| 3137 | 3171 | } |
| 3138 | 3172 | |
| 3139 | 3173 | // __ehdr_start |
| 3140 | 3174 | { |
| 3141 | 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 | 3177 | symbol_ptr.output_section_index = 1; |
| 3144 | 3178 | } |
| 3145 | 3179 | |
| ... | ... | @@ -3149,9 +3183,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3149 | 3183 | const end_sym = self.symbol(self.init_array_end_index.?); |
| 3150 | 3184 | const shdr = &self.shdrs.items[shndx]; |
| 3151 | 3185 | start_sym.output_section_index = shndx; |
| 3152 | start_sym.value = shdr.sh_addr; | |
| 3186 | start_sym.value = @intCast(shdr.sh_addr); | |
| 3153 | 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 | 3191 | // __fini_array_start, __fini_array_end |
| ... | ... | @@ -3160,9 +3194,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3160 | 3194 | const end_sym = self.symbol(self.fini_array_end_index.?); |
| 3161 | 3195 | const shdr = &self.shdrs.items[shndx]; |
| 3162 | 3196 | start_sym.output_section_index = shndx; |
| 3163 | start_sym.value = shdr.sh_addr; | |
| 3197 | start_sym.value = @intCast(shdr.sh_addr); | |
| 3164 | 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 | 3202 | // __preinit_array_start, __preinit_array_end |
| ... | ... | @@ -3171,9 +3205,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3171 | 3205 | const end_sym = self.symbol(self.preinit_array_end_index.?); |
| 3172 | 3206 | const shdr = &self.shdrs.items[shndx]; |
| 3173 | 3207 | start_sym.output_section_index = shndx; |
| 3174 | start_sym.value = shdr.sh_addr; | |
| 3208 | start_sym.value = @intCast(shdr.sh_addr); | |
| 3175 | 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 | 3213 | // _GLOBAL_OFFSET_TABLE_ |
| ... | ... | @@ -3181,14 +3215,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3181 | 3215 | if (self.got_plt_section_index) |shndx| { |
| 3182 | 3216 | const shdr = self.shdrs.items[shndx]; |
| 3183 | 3217 | const sym = self.symbol(self.got_index.?); |
| 3184 | sym.value = shdr.sh_addr; | |
| 3218 | sym.value = @intCast(shdr.sh_addr); | |
| 3185 | 3219 | sym.output_section_index = shndx; |
| 3186 | 3220 | } |
| 3187 | 3221 | } else { |
| 3188 | 3222 | if (self.got_section_index) |shndx| { |
| 3189 | 3223 | const shdr = self.shdrs.items[shndx]; |
| 3190 | 3224 | const sym = self.symbol(self.got_index.?); |
| 3191 | sym.value = shdr.sh_addr; | |
| 3225 | sym.value = @intCast(shdr.sh_addr); | |
| 3192 | 3226 | sym.output_section_index = shndx; |
| 3193 | 3227 | } |
| 3194 | 3228 | } |
| ... | ... | @@ -3197,7 +3231,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3197 | 3231 | if (self.plt_section_index) |shndx| { |
| 3198 | 3232 | const shdr = &self.shdrs.items[shndx]; |
| 3199 | 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 | 3235 | symbol_ptr.output_section_index = shndx; |
| 3202 | 3236 | } |
| 3203 | 3237 | |
| ... | ... | @@ -3205,7 +3239,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3205 | 3239 | if (self.dso_handle_index) |index| { |
| 3206 | 3240 | const shdr = &self.shdrs.items[1]; |
| 3207 | 3241 | const symbol_ptr = self.symbol(index); |
| 3208 | symbol_ptr.value = shdr.sh_addr; | |
| 3242 | symbol_ptr.value = @intCast(shdr.sh_addr); | |
| 3209 | 3243 | symbol_ptr.output_section_index = 0; |
| 3210 | 3244 | } |
| 3211 | 3245 | |
| ... | ... | @@ -3213,7 +3247,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3213 | 3247 | if (self.eh_frame_hdr_section_index) |shndx| { |
| 3214 | 3248 | const shdr = &self.shdrs.items[shndx]; |
| 3215 | 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 | 3251 | symbol_ptr.output_section_index = shndx; |
| 3218 | 3252 | } |
| 3219 | 3253 | |
| ... | ... | @@ -3225,9 +3259,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3225 | 3259 | const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); |
| 3226 | 3260 | const start_sym = self.symbol(self.rela_iplt_start_index.?); |
| 3227 | 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 | 3263 | start_sym.output_section_index = shndx; |
| 3230 | end_sym.value = end_addr; | |
| 3264 | end_sym.value = @intCast(end_addr); | |
| 3231 | 3265 | end_sym.output_section_index = shndx; |
| 3232 | 3266 | } |
| 3233 | 3267 | |
| ... | ... | @@ -3236,7 +3270,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3236 | 3270 | const end_symbol = self.symbol(self.end_index.?); |
| 3237 | 3271 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 3238 | 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 | 3274 | end_symbol.output_section_index = @intCast(shndx); |
| 3241 | 3275 | } |
| 3242 | 3276 | } |
| ... | ... | @@ -3251,9 +3285,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3251 | 3285 | const stop = self.symbol(self.start_stop_indexes.items[index + 1]); |
| 3252 | 3286 | const shndx = self.sectionByName(name["__start_".len..]).?; |
| 3253 | 3287 | const shdr = &self.shdrs.items[shndx]; |
| 3254 | start.value = shdr.sh_addr; | |
| 3288 | start.value = @intCast(shdr.sh_addr); | |
| 3255 | 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 | 3291 | stop.output_section_index = shndx; |
| 3258 | 3292 | } |
| 3259 | 3293 | } |
| ... | ... | @@ -3263,7 +3297,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3263 | 3297 | const sym = self.symbol(index); |
| 3264 | 3298 | if (self.sectionByName(".sdata")) |shndx| { |
| 3265 | 3299 | const shdr = self.shdrs.items[shndx]; |
| 3266 | sym.value = shdr.sh_addr + 0x800; | |
| 3300 | sym.value = @intCast(shdr.sh_addr + 0x800); | |
| 3267 | 3301 | sym.output_section_index = shndx; |
| 3268 | 3302 | } else { |
| 3269 | 3303 | sym.value = 0; |
| ... | ... | @@ -3293,12 +3327,122 @@ fn checkDuplicates(self: *Elf) !void { |
| 3293 | 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 | 3419 | fn initOutputSections(self: *Elf) !void { |
| 3297 | 3420 | for (self.objects.items) |index| { |
| 3298 | 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 | 3446 | fn initSyntheticSections(self: *Elf) !void { |
| 3303 | 3447 | const comp = self.base.comp; |
| 3304 | 3448 | const target = comp.root_mod.resolved_target.result; |
| ... | ... | @@ -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 | 4117 | var output_rela_sections = try self.output_rela_sections.clone(gpa); |
| 3970 | 4118 | defer output_rela_sections.deinit(gpa); |
| ... | ... | @@ -4052,7 +4200,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4052 | 4200 | if (!atom_ptr.flags.alive) continue; |
| 4053 | 4201 | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 4054 | 4202 | const padding = offset - shdr.sh_size; |
| 4055 | atom_ptr.value = offset; | |
| 4203 | atom_ptr.value = @intCast(offset); | |
| 4056 | 4204 | shdr.sh_size += padding + atom_ptr.size; |
| 4057 | 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 | 4683 | const atom_ptr = self.atom(atom_index).?; |
| 4536 | 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 | 4687 | return error.Overflow; |
| 4540 | 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 | 4724 | const thunk_size = th.size(self); |
| 4577 | 4725 | try buffer.ensureUnusedCapacity(thunk_size); |
| 4578 | 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 | 4728 | try th.write(self, buffer.writer()); |
| 4581 | 4729 | assert(buffer.items.len == thunk_size); |
| 4582 | 4730 | try self.base.file.?.pwriteAll(buffer.items, offset); |
| ... | ... | @@ -4611,6 +4759,7 @@ pub fn updateSymtabSize(self: *Elf) !void { |
| 4611 | 4759 | if (self.eh_frame_section_index) |_| { |
| 4612 | 4760 | nlocals += 1; |
| 4613 | 4761 | } |
| 4762 | nlocals += @intCast(self.merge_sections.items.len); | |
| 4614 | 4763 | |
| 4615 | 4764 | if (self.requiresThunks()) for (self.thunks.items) |*th| { |
| 4616 | 4765 | th.output_symtab_ctx.ilocal = nlocals + 1; |
| ... | ... | @@ -4947,12 +5096,30 @@ fn writeSectionSymbols(self: *Elf) void { |
| 4947 | 5096 | }; |
| 4948 | 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 | 5115 | pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 4953 | 5116 | if (self.eh_frame_section_index) |index| { |
| 4954 | 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 | 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 | 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 | 5672 | pub fn addThunk(self: *Elf) !Thunk.Index { |
| 5462 | 5673 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); |
| 5463 | 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 | 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 | 5904 | const shndx = blk: { |
| 5642 | 5905 | if (self.getTarget().cpu.arch == .x86_64 and self.got_plt_section_index != null) |
| 5643 | 5906 | break :blk self.got_plt_section_index.?; |
| 5644 | 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 | 5913 | const index = self.phdr_tls_index orelse return 0; |
| 5651 | 5914 | const phdr = self.phdrs.items[index]; |
| 5652 | return switch (self.getTarget().cpu.arch) { | |
| 5915 | const addr = switch (self.getTarget().cpu.arch) { | |
| 5653 | 5916 | .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), |
| 5654 | 5917 | .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), |
| 5655 | 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 | 5924 | const index = self.phdr_tls_index orelse return 0; |
| 5661 | 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 | 5930 | const index = self.phdr_tls_index orelse return 0; |
| 5667 | 5931 | const phdr = self.phdrs.items[index]; |
| 5668 | return phdr.p_vaddr; | |
| 5932 | return @intCast(phdr.p_vaddr); | |
| 5669 | 5933 | } |
| 5670 | 5934 | |
| 5671 | 5935 | const ErrorWithNotes = struct { |
| ... | ... | @@ -6043,6 +6307,11 @@ fn fmtDumpState( |
| 6043 | 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 | 6315 | try writer.writeAll("\nOutput shdrs\n"); |
| 6047 | 6316 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 6048 | 6317 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ |
| ... | ... | @@ -6235,6 +6504,7 @@ const gc = @import("Elf/gc.zig"); |
| 6235 | 6504 | const glibc = @import("../glibc.zig"); |
| 6236 | 6505 | const link = @import("../link.zig"); |
| 6237 | 6506 | const lldMain = @import("../main.zig").lldMain; |
| 6507 | const merge_section = @import("Elf/merge_section.zig"); | |
| 6238 | 6508 | const musl = @import("../musl.zig"); |
| 6239 | 6509 | const relocatable = @import("Elf/relocatable.zig"); |
| 6240 | 6510 | const relocation = @import("Elf/relocation.zig"); |
| ... | ... | @@ -6260,10 +6530,13 @@ const GnuHashSection = synthetic_sections.GnuHashSection; |
| 6260 | 6530 | const GotSection = synthetic_sections.GotSection; |
| 6261 | 6531 | const GotPltSection = synthetic_sections.GotPltSection; |
| 6262 | 6532 | const HashSection = synthetic_sections.HashSection; |
| 6533 | const InputMergeSection = merge_section.InputMergeSection; | |
| 6263 | 6534 | const LdScript = @import("Elf/LdScript.zig"); |
| 6264 | 6535 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); |
| 6265 | 6536 | const Liveness = @import("../Liveness.zig"); |
| 6266 | 6537 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 6538 | const MergeSection = merge_section.MergeSection; | |
| 6539 | const MergeSubsection = merge_section.MergeSubsection; | |
| 6267 | 6540 | const Module = @import("../Module.zig"); |
| 6268 | 6541 | const Object = @import("Elf/Object.zig"); |
| 6269 | 6542 | const InternPool = @import("../InternPool.zig"); |
src/link/Elf/Atom.zig+187-114| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | /// Address allocated for this Atom. |
| 2 | value: u64 = 0, | |
| 2 | value: i64 = 0, | |
| 3 | 3 | |
| 4 | 4 | /// Name of this Atom. |
| 5 | 5 | name_offset: u32 = 0, |
| ... | ... | @@ -22,32 +22,19 @@ output_section_index: u32 = 0, |
| 22 | 22 | /// Index of the input section containing this atom's relocs. |
| 23 | 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 | 25 | /// Index of this atom in the linker's atoms table. |
| 32 | 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 | 28 | /// Points to the previous and next neighbors, based on the `text_offset`. |
| 47 | 29 | /// This can be used to find, for example, the capacity of this `TextBlock`. |
| 48 | 30 | prev_index: Index = 0, |
| 49 | 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 | 38 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
| 52 | 39 | |
| 53 | 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 | 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 | 48 | const shndx = self.outputShndx() orelse return self.value; |
| 62 | 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 | 65 | 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 | 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 | 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 | 103 | next.address(elf_file) |
| 103 | 104 | else |
| 104 | 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 | 109 | pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { |
| 109 | 110 | // No need to keep a free list node for the last block. |
| 110 | 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 | 113 | const ideal_cap = Elf.padToIdeal(self.size); |
| 113 | 114 | if (cap <= ideal_cap) return false; |
| 114 | 115 | const surplus = cap - ideal_cap; |
| ... | ... | @@ -141,8 +142,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 141 | 142 | // Is it enough that we could fit this new atom? |
| 142 | 143 | const cap = big_atom.capacity(elf_file); |
| 143 | 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 capacity_end_vaddr = big_atom.value + cap; | |
| 145 | const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; | |
| 146 | const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; | |
| 146 | 147 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 147 | 148 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); |
| 148 | 149 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| ... | ... | @@ -167,14 +168,14 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 167 | 168 | if (!keep_free_list_node) { |
| 168 | 169 | free_list_removal = i; |
| 169 | 170 | } |
| 170 | break :blk new_start_vaddr; | |
| 171 | break :blk @intCast(new_start_vaddr); | |
| 171 | 172 | } else if (elf_file.atom(last_atom_index.*)) |last| { |
| 172 | 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 | 175 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); |
| 175 | 176 | // Set up the metadata to be updated, after errors are no longer possible. |
| 176 | 177 | atom_placement = last.atom_index; |
| 177 | break :blk new_start_vaddr; | |
| 178 | break :blk @intCast(new_start_vaddr); | |
| 178 | 179 | } else { |
| 179 | 180 | break :blk 0; |
| 180 | 181 | } |
| ... | ... | @@ -184,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 184 | 185 | self.atom_index, |
| 185 | 186 | self.name(elf_file), |
| 186 | 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 | 191 | const expand_section = if (atom_placement) |placement_index| |
| ... | ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 192 | 193 | else |
| 193 | 194 | true; |
| 194 | 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 | 197 | try elf_file.growAllocSection(self.outputShndx().?, needed_size); |
| 197 | 198 | last_atom_index.* = self.atom_index; |
| 198 | 199 | |
| ... | ... | @@ -242,7 +243,7 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | 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 | 247 | try self.allocate(elf_file); |
| 247 | 248 | } |
| 248 | 249 | |
| ... | ... | @@ -309,11 +310,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void { |
| 309 | 310 | |
| 310 | 311 | pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela { |
| 311 | 312 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; |
| 312 | return switch (self.file(elf_file).?) { | |
| 313 | .zig_object => |x| x.relocs.items[shndx].items, | |
| 314 | .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num], | |
| 313 | switch (self.file(elf_file).?) { | |
| 314 | .zig_object => |x| return x.relocs.items[shndx].items, | |
| 315 | .object => |x| { | |
| 316 | const extras = self.extra(elf_file).?; | |
| 317 | return x.relocs.items[extras.rel_index..][0..extras.rel_count]; | |
| 318 | }, | |
| 315 | 319 | else => unreachable, |
| 316 | }; | |
| 320 | } | |
| 317 | 321 | } |
| 318 | 322 | |
| 319 | 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 | 333 | }; |
| 330 | 334 | const target = elf_file.symbol(target_index); |
| 331 | 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 | 337 | var r_addend = rel.r_addend; |
| 334 | 338 | var r_sym: u32 = 0; |
| 335 | 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 | 344 | r_addend += @intCast(target.address(.{}, elf_file)); |
| 338 | 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 | 366 | } |
| 360 | 367 | |
| 361 | 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 | 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 | 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 | 427 | }; |
| 420 | 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 | 436 | // Check for violation of One Definition Rule for COMDATs. |
| 423 | 437 | if (symbol.file(elf_file) == null) { |
| 424 | 438 | // TODO convert into an error |
| ... | ... | @@ -431,7 +445,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 431 | 445 | } |
| 432 | 446 | |
| 433 | 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 | 451 | if (symbol.isIFunc(elf_file)) { |
| 437 | 452 | symbol.flags.needs_got = true; |
| ... | ... | @@ -743,21 +758,21 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 743 | 758 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ |
| 744 | 759 | // |
| 745 | 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 | 762 | // Addend from the relocation. |
| 748 | 763 | const A = rel.r_addend; |
| 749 | 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 | 766 | // Address of the global offset table. |
| 752 | const GOT = @as(i64, @intCast(elf_file.gotAddress())); | |
| 767 | const GOT = elf_file.gotAddress(); | |
| 753 | 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 | 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 | 772 | // // Address of the thread pointer. |
| 758 | const TP = @as(i64, @intCast(elf_file.tpAddress())); | |
| 773 | const TP = elf_file.tpAddress(); | |
| 759 | 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 | 777 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ |
| 763 | 778 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| ... | ... | @@ -814,9 +829,9 @@ fn resolveDynAbsReloc( |
| 814 | 829 | const comp = elf_file.base.comp; |
| 815 | 830 | const gpa = comp.gpa; |
| 816 | 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 | 833 | const A = rel.r_addend; |
| 819 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | |
| 834 | const S = target.address(.{}, elf_file); | |
| 820 | 835 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; |
| 821 | 836 | |
| 822 | 837 | const num_dynrelocs = switch (self.file(elf_file).?) { |
| ... | ... | @@ -884,7 +899,7 @@ fn resolveDynAbsReloc( |
| 884 | 899 | }, |
| 885 | 900 | |
| 886 | 901 | .ifunc => { |
| 887 | const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file))); | |
| 902 | const S_ = target.address(.{ .plt = false }, elf_file); | |
| 888 | 903 | elf_file.addRelaDynAssumeCapacity(.{ |
| 889 | 904 | .offset = P, |
| 890 | 905 | .type = relocation.encode(.irel, cpu_arch), |
| ... | ... | @@ -924,6 +939,11 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 924 | 939 | else => unreachable, |
| 925 | 940 | }; |
| 926 | 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 | 948 | // Check for violation of One Definition Rule for COMDATs. |
| 929 | 949 | if (target.file(elf_file) == null) { |
| ... | ... | @@ -937,20 +957,21 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 937 | 957 | } |
| 938 | 958 | |
| 939 | 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 | 963 | // We will use equation format to resolve relocations: |
| 943 | 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 | 967 | // Addend from the relocation. |
| 947 | 968 | const A = rel.r_addend; |
| 948 | 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 | 971 | // Address of the global offset table. |
| 951 | const GOT = @as(i64, @intCast(elf_file.gotAddress())); | |
| 972 | const GOT = elf_file.gotAddress(); | |
| 952 | 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 | 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 | 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 | 1037 | pub fn format( |
| 988 | 1038 | atom: Atom, |
| 989 | 1039 | comptime unused_fmt_string: []const u8, |
| ... | ... | @@ -1023,12 +1073,13 @@ fn format2( |
| 1023 | 1073 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), |
| 1024 | 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 | 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 | 1080 | try writer.print("{d}", .{i}); |
| 1030 | 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 | 1084 | try writer.writeAll(" }"); |
| 1034 | 1085 | } |
| ... | ... | @@ -1045,6 +1096,12 @@ pub const Flags = packed struct { |
| 1045 | 1096 | |
| 1046 | 1097 | /// Specifies if the atom has been visited during garbage collection. |
| 1047 | 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 | 1107 | const x86_64 = struct { |
| ... | ... | @@ -1235,10 +1292,10 @@ const x86_64 = struct { |
| 1235 | 1292 | |
| 1236 | 1293 | .TLSGD => { |
| 1237 | 1294 | if (target.flags.has_tlsgd) { |
| 1238 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); | |
| 1295 | const S_ = target.tlsGdAddress(elf_file); | |
| 1239 | 1296 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1240 | 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 | 1299 | try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream); |
| 1243 | 1300 | } else { |
| 1244 | 1301 | try x86_64.relaxTlsGdToLe( |
| ... | ... | @@ -1254,13 +1311,13 @@ const x86_64 = struct { |
| 1254 | 1311 | .TLSLD => { |
| 1255 | 1312 | if (elf_file.got.tlsld_index) |entry_index| { |
| 1256 | 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 | 1315 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1259 | 1316 | } else { |
| 1260 | 1317 | try x86_64.relaxTlsLdToLe( |
| 1261 | 1318 | atom, |
| 1262 | 1319 | &.{ rel, it.next().? }, |
| 1263 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), | |
| 1320 | @as(i32, @intCast(TP - elf_file.tlsAddress())), | |
| 1264 | 1321 | elf_file, |
| 1265 | 1322 | stream, |
| 1266 | 1323 | ); |
| ... | ... | @@ -1269,7 +1326,7 @@ const x86_64 = struct { |
| 1269 | 1326 | |
| 1270 | 1327 | .GOTPC32_TLSDESC => { |
| 1271 | 1328 | if (target.flags.has_tlsdesc) { |
| 1272 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); | |
| 1329 | const S_ = target.tlsDescAddress(elf_file); | |
| 1273 | 1330 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1274 | 1331 | } else { |
| 1275 | 1332 | x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch { |
| ... | ... | @@ -1293,7 +1350,7 @@ const x86_64 = struct { |
| 1293 | 1350 | |
| 1294 | 1351 | .GOTTPOFF => { |
| 1295 | 1352 | if (target.flags.has_gottp) { |
| 1296 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | |
| 1353 | const S_ = target.gotTpAddress(elf_file); | |
| 1297 | 1354 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1298 | 1355 | } else { |
| 1299 | 1356 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]); |
| ... | ... | @@ -1336,9 +1393,18 @@ const x86_64 = struct { |
| 1336 | 1393 | .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), |
| 1337 | 1394 | .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), |
| 1338 | 1395 | .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), |
| 1339 | .@"64" => try cwriter.writeInt(i64, S + A, .little), | |
| 1340 | .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), | |
| 1341 | .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | |
| 1396 | .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value| | |
| 1397 | try cwriter.writeInt(u64, value, .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 | 1408 | .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), |
| 1343 | 1409 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), |
| 1344 | 1410 | .SIZE32 => { |
| ... | ... | @@ -1720,7 +1786,7 @@ const aarch64 = struct { |
| 1720 | 1786 | .object => |x| x.symbols.items[rel.r_sym()], |
| 1721 | 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 | 1790 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 1725 | 1791 | }; |
| 1726 | 1792 | aarch64_util.writeBranchImm(disp, code); |
| ... | ... | @@ -1738,16 +1804,12 @@ const aarch64 = struct { |
| 1738 | 1804 | |
| 1739 | 1805 | .ADR_PREL_PG_HI21 => { |
| 1740 | 1806 | // TODO: check for relaxation of ADRP+ADD |
| 1741 | const saddr = @as(u64, @intCast(P)); | |
| 1742 | const taddr = @as(u64, @intCast(S + A)); | |
| 1743 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); | |
| 1807 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A))); | |
| 1744 | 1808 | aarch64_util.writeAdrpInst(pages, code); |
| 1745 | 1809 | }, |
| 1746 | 1810 | |
| 1747 | 1811 | .ADR_GOT_PAGE => if (target.flags.has_got) { |
| 1748 | const saddr = @as(u64, @intCast(P)); | |
| 1749 | const taddr = @as(u64, @intCast(G + GOT + A)); | |
| 1750 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); | |
| 1812 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A))); | |
| 1751 | 1813 | aarch64_util.writeAdrpInst(pages, code); |
| 1752 | 1814 | } else { |
| 1753 | 1815 | // TODO: relax |
| ... | ... | @@ -1802,46 +1864,38 @@ const aarch64 = struct { |
| 1802 | 1864 | }, |
| 1803 | 1865 | |
| 1804 | 1866 | .TLSIE_ADR_GOTTPREL_PAGE21 => { |
| 1805 | const S_: i64 = @intCast(target.gotTpAddress(elf_file)); | |
| 1806 | const saddr: u64 = @intCast(P); | |
| 1807 | const taddr: u64 = @intCast(S_ + A); | |
| 1808 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1809 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | |
| 1867 | const S_ = target.gotTpAddress(elf_file); | |
| 1868 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1869 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1810 | 1870 | aarch64_util.writeAdrpInst(pages, code); |
| 1811 | 1871 | }, |
| 1812 | 1872 | |
| 1813 | 1873 | .TLSIE_LD64_GOTTPREL_LO12_NC => { |
| 1814 | const S_: i64 = @intCast(target.gotTpAddress(elf_file)); | |
| 1815 | const taddr: u64 = @intCast(S_ + A); | |
| 1816 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1817 | const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); | |
| 1874 | const S_ = target.gotTpAddress(elf_file); | |
| 1875 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1876 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1818 | 1877 | aarch64_util.writeLoadStoreRegInst(offset, code); |
| 1819 | 1878 | }, |
| 1820 | 1879 | |
| 1821 | 1880 | .TLSGD_ADR_PAGE21 => { |
| 1822 | const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); | |
| 1823 | const saddr: u64 = @intCast(P); | |
| 1824 | const taddr: u64 = @intCast(S_ + A); | |
| 1825 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1826 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | |
| 1881 | const S_ = target.tlsGdAddress(elf_file); | |
| 1882 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1883 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1827 | 1884 | aarch64_util.writeAdrpInst(pages, code); |
| 1828 | 1885 | }, |
| 1829 | 1886 | |
| 1830 | 1887 | .TLSGD_ADD_LO12_NC => { |
| 1831 | const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); | |
| 1832 | const taddr: u64 = @intCast(S_ + A); | |
| 1833 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1834 | const offset: u12 = @truncate(taddr); | |
| 1888 | const S_ = target.tlsGdAddress(elf_file); | |
| 1889 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1890 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1835 | 1891 | aarch64_util.writeAddImmInst(offset, code); |
| 1836 | 1892 | }, |
| 1837 | 1893 | |
| 1838 | 1894 | .TLSDESC_ADR_PAGE21 => { |
| 1839 | 1895 | if (target.flags.has_tlsdesc) { |
| 1840 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | |
| 1841 | const saddr: u64 = @intCast(P); | |
| 1842 | const taddr: u64 = @intCast(S_ + A); | |
| 1843 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1844 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); | |
| 1896 | const S_ = target.tlsDescAddress(elf_file); | |
| 1897 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1898 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1845 | 1899 | aarch64_util.writeAdrpInst(pages, code); |
| 1846 | 1900 | } else { |
| 1847 | 1901 | relocs_log.debug(" relaxing adrp => nop", .{}); |
| ... | ... | @@ -1851,10 +1905,9 @@ const aarch64 = struct { |
| 1851 | 1905 | |
| 1852 | 1906 | .TLSDESC_LD64_LO12 => { |
| 1853 | 1907 | if (target.flags.has_tlsdesc) { |
| 1854 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | |
| 1855 | const taddr: u64 = @intCast(S_ + A); | |
| 1856 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1857 | const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); | |
| 1908 | const S_ = target.tlsDescAddress(elf_file); | |
| 1909 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1910 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1858 | 1911 | aarch64_util.writeLoadStoreRegInst(offset, code); |
| 1859 | 1912 | } else { |
| 1860 | 1913 | relocs_log.debug(" relaxing ldr => nop", .{}); |
| ... | ... | @@ -1864,10 +1917,9 @@ const aarch64 = struct { |
| 1864 | 1917 | |
| 1865 | 1918 | .TLSDESC_ADD_LO12 => { |
| 1866 | 1919 | if (target.flags.has_tlsdesc) { |
| 1867 | const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); | |
| 1868 | const taddr: u64 = @intCast(S_ + A); | |
| 1869 | relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); | |
| 1870 | const offset: u12 = @truncate(taddr); | |
| 1920 | const S_ = target.tlsDescAddress(elf_file); | |
| 1921 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); | |
| 1922 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1871 | 1923 | aarch64_util.writeAddImmInst(offset, code); |
| 1872 | 1924 | } else { |
| 1873 | 1925 | const old_inst = Instruction{ |
| ... | ... | @@ -1912,7 +1964,6 @@ const aarch64 = struct { |
| 1912 | 1964 | ) !void { |
| 1913 | 1965 | _ = it; |
| 1914 | 1966 | _ = code; |
| 1915 | _ = target; | |
| 1916 | 1967 | |
| 1917 | 1968 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); |
| 1918 | 1969 | const cwriter = stream.writer(); |
| ... | ... | @@ -1922,7 +1973,10 @@ const aarch64 = struct { |
| 1922 | 1973 | switch (r_type) { |
| 1923 | 1974 | .NONE => unreachable, |
| 1924 | 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 | 1980 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 1927 | 1981 | } |
| 1928 | 1982 | } |
| ... | ... | @@ -2047,7 +2101,7 @@ const riscv = struct { |
| 2047 | 2101 | const atom_addr = atom.address(elf_file); |
| 2048 | 2102 | const pos = it.pos; |
| 2049 | 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 | 2105 | } else { |
| 2052 | 2106 | // TODO: implement searching forward |
| 2053 | 2107 | var err = try elf_file.addErrorWithNotes(1); |
| ... | ... | @@ -2065,10 +2119,10 @@ const riscv = struct { |
| 2065 | 2119 | .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]), |
| 2066 | 2120 | else => unreachable, |
| 2067 | 2121 | }; |
| 2068 | const S_ = @as(i64, @intCast(target_.address(.{}, elf_file))); | |
| 2122 | const S_ = target_.address(.{}, elf_file); | |
| 2069 | 2123 | const A_ = pair.r_addend; |
| 2070 | const P_ = @as(i64, @intCast(atom_addr + pair.r_offset)); | |
| 2071 | const G_ = @as(i64, @intCast(target_.gotAddress(elf_file))) - GOT; | |
| 2124 | const P_ = atom_addr + @as(i64, @intCast(pair.r_offset)); | |
| 2125 | const G_ = target_.gotAddress(elf_file) - GOT; | |
| 2072 | 2126 | const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) { |
| 2073 | 2127 | .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow, |
| 2074 | 2128 | .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow, |
| ... | ... | @@ -2096,7 +2150,6 @@ const riscv = struct { |
| 2096 | 2150 | code: []u8, |
| 2097 | 2151 | stream: anytype, |
| 2098 | 2152 | ) !void { |
| 2099 | _ = target; | |
| 2100 | 2153 | _ = it; |
| 2101 | 2154 | |
| 2102 | 2155 | const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); |
| ... | ... | @@ -2111,7 +2164,10 @@ const riscv = struct { |
| 2111 | 2164 | .NONE => unreachable, |
| 2112 | 2165 | |
| 2113 | 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 | 2172 | .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A), |
| 2117 | 2173 | .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A), |
| ... | ... | @@ -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 | 2246 | const std = @import("std"); |
| 2174 | 2247 | const assert = std.debug.assert; |
| 2175 | 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 | 60 | if (file_ptr.index() != self.index) continue; |
| 61 | 61 | global.flags.output_symtab = true; |
| 62 | 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 | 64 | self.output_symtab_ctx.nlocals += 1; |
| 65 | 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 | 67 | self.output_symtab_ctx.nglobals += 1; |
| 68 | 68 | } |
| 69 | 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 | 15 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, |
| 16 | 16 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 17 | 17 | |
| 18 | merge_sections: std.ArrayListUnmanaged(InputMergeSection.Index) = .{}, | |
| 19 | ||
| 18 | 20 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 19 | 21 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 20 | 22 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, |
| ... | ... | @@ -51,6 +53,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 51 | 53 | self.fdes.deinit(allocator); |
| 52 | 54 | self.cies.deinit(allocator); |
| 53 | 55 | self.eh_frame_data.deinit(allocator); |
| 56 | self.merge_sections.deinit(allocator); | |
| 54 | 57 | } |
| 55 | 58 | |
| 56 | 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 | 245 | const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); |
| 243 | 246 | defer allocator.free(relocs); |
| 244 | 247 | atom.relocs_section_index = @intCast(i); |
| 245 | atom.rel_index = @intCast(self.relocs.items.len); | |
| 246 | atom.rel_num = @intCast(relocs.len); | |
| 248 | const rel_index: u32 = @intCast(self.relocs.items.len); | |
| 249 | const rel_count: u32 = @intCast(relocs.len); | |
| 250 | try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file); | |
| 247 | 251 | try self.relocs.appendUnalignedSlice(allocator, relocs); |
| 248 | 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 | 283 | const name = blk: { |
| 280 | 284 | const name = self.getString(shdr.sh_name); |
| 281 | 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) | |
| 283 | break :blk name; // TODO: consider dropping SHF_STRINGS once ICF is implemented | |
| 286 | if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; | |
| 284 | 287 | const sh_name_prefixes: []const [:0]const u8 = &.{ |
| 285 | 288 | ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", |
| 286 | 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 | 337 | const name = self.getString(shdr.sh_name); |
| 335 | 338 | const ignore = blk: { |
| 336 | 339 | if (mem.startsWith(u8, name, ".note")) break :blk true; |
| 337 | if (mem.startsWith(u8, name, ".comment")) break :blk true; | |
| 338 | 340 | if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; |
| 339 | 341 | if (mem.startsWith(u8, name, ".riscv.attributes")) break :blk true; // TODO: riscv attributes |
| 340 | 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 | 355 | const index = try elf_file.addSymbol(); |
| 354 | 356 | self.symbols.appendAssumeCapacity(index); |
| 355 | 357 | const sym_ptr = elf_file.symbol(index); |
| 356 | sym_ptr.value = sym.st_value; | |
| 358 | sym_ptr.value = @intCast(sym.st_value); | |
| 357 | 359 | sym_ptr.name_offset = sym.st_name; |
| 358 | 360 | sym_ptr.esym_index = @as(u32, @intCast(i)); |
| 359 | 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 | 447 | while (i < self.fdes.items.len) { |
| 446 | 448 | const fde = self.fdes.items[i]; |
| 447 | 449 | const atom = fde.atom(elf_file); |
| 448 | atom.fde_start = i; | |
| 450 | const start = i; | |
| 449 | 451 | i += 1; |
| 450 | 452 | while (i < self.fdes.items.len) : (i += 1) { |
| 451 | 453 | const next_fde = self.fdes.items[i]; |
| 452 | 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 | 548 | elf.SHN_ABS, elf.SHN_COMMON => 0, |
| 546 | 549 | else => self.atoms.items[esym.st_shndx], |
| 547 | 550 | }; |
| 548 | global.value = esym.st_value; | |
| 551 | global.value = @intCast(esym.st_value); | |
| 549 | 552 | global.atom_index = atom_index; |
| 550 | 553 | global.esym_index = esym_index; |
| 551 | 554 | global.file_index = self.index; |
| ... | ... | @@ -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 | 835 | /// We will create dummy shdrs per each resolved common symbols to make it |
| 661 | 836 | /// play nicely with the rest of the system. |
| 662 | 837 | pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { |
| ... | ... | @@ -747,6 +922,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { |
| 747 | 922 | |
| 748 | 923 | for (self.locals()) |local_index| { |
| 749 | 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 | 930 | const atom = local.atom(elf_file) orelse continue; |
| 751 | 931 | if (!atom.flags.alive) continue; |
| 752 | 932 | local.output_section_index = atom.output_section_index; |
| ... | ... | @@ -754,11 +934,23 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { |
| 754 | 934 | |
| 755 | 935 | for (self.globals()) |global_index| { |
| 756 | 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 | 943 | const atom = global.atom(elf_file) orelse continue; |
| 758 | 944 | if (!atom.flags.alive) continue; |
| 759 | if (global.file(elf_file).?.index() != self.index) continue; | |
| 760 | 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 | 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 | 1035 | } |
| 844 | 1036 | |
| 845 | 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 | 1046 | for (self.locals()) |local_index| { |
| 847 | 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 | 1049 | const esym = local.elfSym(elf_file); |
| 850 | 1050 | switch (esym.st_type()) { |
| 851 | 1051 | elf.STT_SECTION => continue, |
| ... | ... | @@ -853,7 +1053,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| 853 | 1053 | else => {}, |
| 854 | 1054 | } |
| 855 | 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 | 1057 | self.output_symtab_ctx.nlocals += 1; |
| 858 | 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 | 1062 | const global = elf_file.symbol(global_index); |
| 863 | 1063 | const file_ptr = global.file(elf_file) orelse continue; |
| 864 | 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 | 1066 | global.flags.output_symtab = true; |
| 867 | 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 | 1069 | self.output_symtab_ctx.nlocals += 1; |
| 870 | 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 | 1072 | self.output_symtab_ctx.nglobals += 1; |
| 873 | 1073 | } |
| 874 | 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 | 1102 | |
| 903 | 1103 | pub fn locals(self: Object) []const Symbol.Index { |
| 904 | 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 | 1107 | return self.symbols.items[0..end]; |
| 907 | 1108 | } |
| 908 | 1109 | |
| 909 | 1110 | pub fn globals(self: Object) []const Symbol.Index { |
| 910 | 1111 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; |
| 911 | const start = self.first_global orelse self.symbols.items.len; | |
| 912 | return self.symbols.items[start..]; | |
| 1112 | assert(self.symbols.items.len >= self.symtab.items.len); | |
| 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 | 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 | 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 | 1167 | /// Caller owns the memory. |
| 958 | 1168 | fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { |
| 959 | 1169 | assert(index < self.shdrs.items.len); |
| ... | ... | @@ -1159,5 +1369,6 @@ const Cie = eh_frame.Cie; |
| 1159 | 1369 | const Elf = @import("../Elf.zig"); |
| 1160 | 1370 | const Fde = eh_frame.Fde; |
| 1161 | 1371 | const File = @import("file.zig").File; |
| 1372 | const InputMergeSection = @import("merge_section.zig").InputMergeSection; | |
| 1162 | 1373 | const Symbol = @import("Symbol.zig"); |
| 1163 | 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 | 231 | |
| 232 | 232 | const global = elf_file.symbol(index); |
| 233 | 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 | 235 | global.atom_index = 0; |
| 236 | 236 | global.esym_index = esym_index; |
| 237 | 237 | global.version_index = self.versyms.items[esym_index]; |
| ... | ... | @@ -269,7 +269,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void { |
| 269 | 269 | if (file_ptr.index() != self.index) continue; |
| 270 | 270 | if (global.isLocal(elf_file)) continue; |
| 271 | 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 | 273 | self.output_symtab_ctx.nglobals += 1; |
| 274 | 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 | 1 | //! Represents a defined symbol. |
| 2 | 2 | |
| 3 | 3 | /// Allocated address value of this symbol. |
| 4 | value: u64 = 0, | |
| 4 | value: i64 = 0, | |
| 5 | 5 | |
| 6 | 6 | /// Offset into the linker's string table. |
| 7 | 7 | name_offset: u32 = 0, |
| ... | ... | @@ -14,7 +14,7 @@ file_index: File.Index = 0, |
| 14 | 14 | /// Use `atom` to get the pointer to the atom. |
| 15 | 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 | 18 | output_section_index: u32 = 0, |
| 19 | 19 | |
| 20 | 20 | /// Index of the source symbol this symbol references. |
| ... | ... | @@ -33,7 +33,8 @@ extra_index: u32 = 0, |
| 33 | 33 | pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { |
| 34 | 34 | const file_ptr = symbol.file(elf_file).?; |
| 35 | 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 | 38 | file_ptr != .linker_defined; |
| 38 | 39 | } |
| 39 | 40 | |
| ... | ... | @@ -70,6 +71,12 @@ pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom { |
| 70 | 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 | 80 | pub fn file(symbol: Symbol, elf_file: *Elf) ?File { |
| 74 | 81 | return elf_file.file(symbol.file_index); |
| 75 | 82 | } |
| ... | ... | @@ -92,7 +99,11 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { |
| 92 | 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 | 107 | if (symbol.flags.has_copy_rel) { |
| 97 | 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 | 119 | if (!atom_ptr.flags.alive) { |
| 109 | 120 | if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) { |
| 110 | 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 | 127 | if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or |
| 112 | 128 | mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or |
| 113 | 129 | mem.startsWith(u8, sym_name, ".eh_frame_seg") or |
| 114 | 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 | 135 | if (mem.startsWith(u8, sym_name, "__FRAME_END__") or |
| 120 | 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.?]; | |
| 123 | return shdr.sh_addr + shdr.sh_size; | |
| 138 | return @intCast(sh_addr + sh_size); | |
| 124 | 139 | } |
| 125 | 140 | |
| 126 | 141 | // TODO I think we potentially should error here |
| ... | ... | @@ -143,65 +158,57 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 { |
| 143 | 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 { | |
| 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 { | |
| 161 | pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 { | |
| 155 | 162 | if (!symbol.flags.has_got) return 0; |
| 156 | 163 | const extras = symbol.extra(elf_file).?; |
| 157 | 164 | const entry = elf_file.got.entries.items[extras.got]; |
| 158 | 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 | 169 | if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0; |
| 163 | 170 | const extras = symbol.extra(elf_file).?; |
| 164 | 171 | const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; |
| 165 | 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 | 177 | if (!symbol.flags.has_plt) return 0; |
| 171 | 178 | const extras = symbol.extra(elf_file).?; |
| 172 | 179 | const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; |
| 173 | 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 | 185 | if (!symbol.flags.has_plt) return 0; |
| 179 | 186 | const extras = symbol.extra(elf_file).?; |
| 180 | 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 | 192 | if (!symbol.flags.has_copy_rel) return 0; |
| 186 | 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 | 198 | if (!symbol.flags.has_tlsgd) return 0; |
| 192 | 199 | const extras = symbol.extra(elf_file).?; |
| 193 | 200 | const entry = elf_file.got.entries.items[extras.tlsgd]; |
| 194 | 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 | 205 | if (!symbol.flags.has_gottp) return 0; |
| 199 | 206 | const extras = symbol.extra(elf_file).?; |
| 200 | 207 | const entry = elf_file.got.entries.items[extras.gottp]; |
| 201 | 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 | 212 | if (!symbol.flags.has_tlsdesc) return 0; |
| 206 | 213 | const extras = symbol.extra(elf_file).?; |
| 207 | 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 | 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 | 232 | if (!symbol.flags.has_zig_got) return 0; |
| 226 | 233 | const extras = symbol.extra(elf_file).?; |
| 227 | 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 | 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 { | |
| 244 | symbol.extra_index = try elf_file.addSymbolExtra(extras); | |
| 250 | const AddExtraOpts = struct { | |
| 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 | 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 | 296 | if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.copy_rel_section_index.?); |
| 267 | 297 | if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; |
| 268 | 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 | 300 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; |
| 270 | 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 | 315 | out.st_info = (st_bind << 4) | st_type; |
| 285 | 316 | out.st_other = esym.st_other; |
| 286 | 317 | out.st_shndx = st_shndx; |
| 287 | out.st_value = st_value; | |
| 318 | out.st_value = @intCast(st_value); | |
| 288 | 319 | out.st_size = esym.st_size; |
| 289 | 320 | } |
| 290 | 321 | |
| ... | ... | @@ -436,6 +467,9 @@ pub const Flags = packed struct { |
| 436 | 467 | /// TODO this is really not needed if only we operated on esyms between |
| 437 | 468 | /// codegen and ZigObject. |
| 438 | 469 | is_tls: bool = false, |
| 470 | ||
| 471 | /// Whether the symbol is a merge subsection. | |
| 472 | merge_subsection: bool = false, | |
| 439 | 473 | }; |
| 440 | 474 | |
| 441 | 475 | pub const Extra = struct { |
| ... | ... | @@ -449,6 +483,7 @@ pub const Extra = struct { |
| 449 | 483 | gottp: u32 = 0, |
| 450 | 484 | tlsdesc: u32 = 0, |
| 451 | 485 | zig_got: u32 = 0, |
| 486 | subsection: u32 = 0, | |
| 452 | 487 | }; |
| 453 | 488 | |
| 454 | 489 | pub const Index = u32; |
| ... | ... | @@ -465,6 +500,7 @@ const File = @import("file.zig").File; |
| 465 | 500 | const GotSection = synthetic_sections.GotSection; |
| 466 | 501 | const GotPltSection = synthetic_sections.GotPltSection; |
| 467 | 502 | const LinkerDefined = @import("LinkerDefined.zig"); |
| 503 | const MergeSubsection = @import("merge_section.zig").MergeSubsection; | |
| 468 | 504 | const Object = @import("Object.zig"); |
| 469 | 505 | const PltSection = synthetic_sections.PltSection; |
| 470 | 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 | 343 | atom.outputShndx().? |
| 344 | 344 | else |
| 345 | 345 | elf.SHN_UNDEF; |
| 346 | global.value = esym.st_value; | |
| 346 | global.value = @intCast(esym.st_value); | |
| 347 | 347 | global.atom_index = atom_index; |
| 348 | 348 | global.esym_index = esym_index; |
| 349 | 349 | global.file_index = self.index; |
| ... | ... | @@ -566,7 +566,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { |
| 566 | 566 | else => {}, |
| 567 | 567 | } |
| 568 | 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 | 570 | self.output_symtab_ctx.nlocals += 1; |
| 571 | 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 | 578 | if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue; |
| 579 | 579 | global.flags.output_symtab = true; |
| 580 | 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 | 582 | self.output_symtab_ctx.nlocals += 1; |
| 583 | 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 | 585 | self.output_symtab_ctx.nglobals += 1; |
| 586 | 586 | } |
| 587 | 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 | 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 | 635 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; |
| 636 | 636 | const code = try gpa.alloc(u8, size); |
| 637 | 637 | errdefer gpa.free(code); |
| ... | ... | @@ -659,7 +659,7 @@ pub fn getDeclVAddr( |
| 659 | 659 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, |
| 660 | 660 | .r_addend = reloc_info.addend, |
| 661 | 661 | }); |
| 662 | return vaddr; | |
| 662 | return @intCast(vaddr); | |
| 663 | 663 | } |
| 664 | 664 | |
| 665 | 665 | pub fn getAnonDeclVAddr( |
| ... | ... | @@ -678,7 +678,7 @@ pub fn getAnonDeclVAddr( |
| 678 | 678 | .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, |
| 679 | 679 | .r_addend = reloc_info.addend, |
| 680 | 680 | }); |
| 681 | return vaddr; | |
| 681 | return @intCast(vaddr); | |
| 682 | 682 | } |
| 683 | 683 | |
| 684 | 684 | pub fn lowerAnonDecl( |
| ... | ... | @@ -929,7 +929,7 @@ fn updateDeclCode( |
| 929 | 929 | |
| 930 | 930 | if (old_size > 0 and elf_file.base.child_pid == null) { |
| 931 | 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 | 933 | if (need_realloc) { |
| 934 | 934 | try atom_ptr.grow(elf_file); |
| 935 | 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 | 984 | |
| 985 | 985 | const shdr = elf_file.shdrs.items[shdr_index]; |
| 986 | 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 | 988 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 989 | 989 | } |
| 990 | 990 | } |
| ... | ... | @@ -1107,7 +1107,7 @@ pub fn updateFunc( |
| 1107 | 1107 | try self.dwarf.?.commitDeclState( |
| 1108 | 1108 | mod, |
| 1109 | 1109 | decl_index, |
| 1110 | sym.address(.{}, elf_file), | |
| 1110 | @intCast(sym.address(.{}, elf_file)), | |
| 1111 | 1111 | sym.atom(elf_file).?.size, |
| 1112 | 1112 | ds, |
| 1113 | 1113 | ); |
| ... | ... | @@ -1186,7 +1186,7 @@ pub fn updateDecl( |
| 1186 | 1186 | try self.dwarf.?.commitDeclState( |
| 1187 | 1187 | mod, |
| 1188 | 1188 | decl_index, |
| 1189 | sym.address(.{}, elf_file), | |
| 1189 | @intCast(sym.address(.{}, elf_file)), | |
| 1190 | 1190 | sym.atom(elf_file).?.size, |
| 1191 | 1191 | ds, |
| 1192 | 1192 | ); |
| ... | ... | @@ -1275,7 +1275,7 @@ fn updateLazySymbol( |
| 1275 | 1275 | } |
| 1276 | 1276 | |
| 1277 | 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 | 1279 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 1280 | 1280 | } |
| 1281 | 1281 | |
| ... | ... | @@ -1373,7 +1373,7 @@ fn lowerConst( |
| 1373 | 1373 | local_esym.st_value = 0; |
| 1374 | 1374 | |
| 1375 | 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 | 1377 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 1378 | 1378 | |
| 1379 | 1379 | return .{ .ok = sym_index }; |
| ... | ... | @@ -1457,7 +1457,7 @@ pub fn updateExports( |
| 1457 | 1457 | |
| 1458 | 1458 | const actual_esym_index = global_esym_index & symbol_mask; |
| 1459 | 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 | 1461 | global_esym.st_shndx = esym.st_shndx; |
| 1462 | 1462 | global_esym.st_info = (stb_bits << 4) | stt_bits; |
| 1463 | 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 | 68 | } |
| 69 | 69 | |
| 70 | 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 | 75 | const atom = sym.atom(elf_file) orelse return; |
| 72 | 76 | if (markAtom(atom)) try roots.append(atom); |
| 73 | 77 | } |
| ... | ... | @@ -96,6 +100,10 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { |
| 96 | 100 | |
| 97 | 101 | for (atom.relocs(elf_file)) |rel| { |
| 98 | 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 | 107 | const target_atom = target_sym.atom(elf_file) orelse continue; |
| 100 | 108 | target_atom.flags.alive = true; |
| 101 | 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 | 34 | // First, we flush relocatable object file generated with our backends. |
| 35 | 35 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 36 | 36 | zig_object.resolveSymbols(elf_file); |
| 37 | try elf_file.addCommentString(); | |
| 38 | try elf_file.finalizeMergeSections(); | |
| 37 | 39 | zig_object.claimUnresolvedObject(elf_file); |
| 38 | 40 | |
| 41 | try elf_file.initMergeSections(); | |
| 39 | 42 | try elf_file.initSymtab(); |
| 40 | 43 | try elf_file.initShStrtab(); |
| 41 | 44 | try elf_file.sortShdrs(); |
| 42 | 45 | try zig_object.addAtomsToRelaSections(elf_file); |
| 46 | try elf_file.updateMergeSectionSizes(); | |
| 43 | 47 | try updateSectionSizes(elf_file); |
| 44 | 48 | |
| 45 | 49 | try allocateAllocSections(elf_file); |
| ... | ... | @@ -49,6 +53,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 49 | 53 | state_log.debug("{}", .{elf_file.dumpState()}); |
| 50 | 54 | } |
| 51 | 55 | |
| 56 | try elf_file.writeMergeSections(); | |
| 52 | 57 | try writeSyntheticSections(elf_file); |
| 53 | 58 | try elf_file.writeShdrTable(); |
| 54 | 59 | try elf_file.writeElfHeader(); |
| ... | ... | @@ -179,9 +184,13 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 179 | 184 | // input Object files. |
| 180 | 185 | elf_file.resolveSymbols(); |
| 181 | 186 | elf_file.markEhFrameAtomsDead(); |
| 187 | try elf_file.resolveMergeSections(); | |
| 188 | try elf_file.addCommentString(); | |
| 189 | try elf_file.finalizeMergeSections(); | |
| 182 | 190 | claimUnresolved(elf_file); |
| 183 | 191 | |
| 184 | 192 | try initSections(elf_file); |
| 193 | try elf_file.initMergeSections(); | |
| 185 | 194 | try elf_file.sortShdrs(); |
| 186 | 195 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 187 | 196 | try zig_object.addAtomsToRelaSections(elf_file); |
| ... | ... | @@ -191,6 +200,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 191 | 200 | try object.addAtomsToOutputSections(elf_file); |
| 192 | 201 | try object.addAtomsToRelaSections(elf_file); |
| 193 | 202 | } |
| 203 | try elf_file.updateMergeSectionSizes(); | |
| 194 | 204 | try updateSectionSizes(elf_file); |
| 195 | 205 | |
| 196 | 206 | try allocateAllocSections(elf_file); |
| ... | ... | @@ -201,6 +211,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 201 | 211 | } |
| 202 | 212 | |
| 203 | 213 | try writeAtoms(elf_file); |
| 214 | try elf_file.writeMergeSections(); | |
| 204 | 215 | try writeSyntheticSections(elf_file); |
| 205 | 216 | try elf_file.writeShdrTable(); |
| 206 | 217 | try elf_file.writeElfHeader(); |
| ... | ... | @@ -328,7 +339,7 @@ fn updateSectionSizes(elf_file: *Elf) !void { |
| 328 | 339 | if (!atom_ptr.flags.alive) continue; |
| 329 | 340 | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 330 | 341 | const padding = offset - shdr.sh_size; |
| 331 | atom_ptr.value = offset; | |
| 342 | atom_ptr.value = @intCast(offset); | |
| 332 | 343 | shdr.sh_size += padding + atom_ptr.size; |
| 333 | 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 | 445 | const atom_ptr = elf_file.atom(atom_index).?; |
| 435 | 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 | 449 | return error.Overflow; |
| 439 | 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 | 259 | if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { |
| 260 | 260 | zig_got.flags.needs_rela = true; |
| 261 | 261 | } |
| 262 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 262 | try symbol.addExtra(.{ .zig_got = index }, elf_file); | |
| 267 | 263 | return index; |
| 268 | 264 | } |
| 269 | 265 | |
| ... | ... | @@ -274,11 +270,11 @@ pub const ZigGotSection = struct { |
| 274 | 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 | 274 | _ = zig_got; |
| 279 | 275 | const entry_size = elf_file.archPtrWidthBytes(); |
| 280 | 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 | 280 | pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize { |
| ... | ... | @@ -295,23 +291,23 @@ pub const ZigGotSection = struct { |
| 295 | 291 | const target = elf_file.getTarget(); |
| 296 | 292 | const endian = target.cpu.arch.endian(); |
| 297 | 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 | 295 | const entry = zig_got.entries.items[index]; |
| 300 | 296 | const value = elf_file.symbol(entry).address(.{}, elf_file); |
| 301 | 297 | switch (entry_size) { |
| 302 | 298 | 2 => { |
| 303 | 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 | 301 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 306 | 302 | }, |
| 307 | 303 | 4 => { |
| 308 | 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 | 306 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 311 | 307 | }, |
| 312 | 308 | 8 => { |
| 313 | 309 | var buf: [8]u8 = undefined; |
| 314 | std.mem.writeInt(u64, &buf, value, endian); | |
| 310 | std.mem.writeInt(u64, &buf, @intCast(value), endian); | |
| 315 | 311 | try elf_file.base.file.?.pwriteAll(&buf, off); |
| 316 | 312 | |
| 317 | 313 | if (elf_file.base.child_pid) |pid| { |
| ... | ... | @@ -360,9 +356,9 @@ pub const ZigGotSection = struct { |
| 360 | 356 | const symbol = elf_file.symbol(entry); |
| 361 | 357 | const offset = symbol.zigGotAddress(elf_file); |
| 362 | 358 | elf_file.addRelaDynAssumeCapacity(.{ |
| 363 | .offset = offset, | |
| 359 | .offset = @intCast(offset), | |
| 364 | 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 | 386 | .st_info = elf.STT_OBJECT, |
| 391 | 387 | .st_other = 0, |
| 392 | 388 | .st_shndx = @intCast(elf_file.zig_got_section_index.?), |
| 393 | .st_value = st_value, | |
| 389 | .st_value = @intCast(st_value), | |
| 394 | 390 | .st_size = st_size, |
| 395 | 391 | }; |
| 396 | 392 | } |
| ... | ... | @@ -461,10 +457,10 @@ pub const GotSection = struct { |
| 461 | 457 | }; |
| 462 | 458 | } |
| 463 | 459 | |
| 464 | pub fn address(entry: Entry, elf_file: *Elf) u64 { | |
| 465 | const ptr_bytes = @as(u64, elf_file.archPtrWidthBytes()); | |
| 460 | pub fn address(entry: Entry, elf_file: *Elf) i64 { | |
| 461 | const ptr_bytes = elf_file.archPtrWidthBytes(); | |
| 466 | 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 | 495 | { |
| 500 | 496 | got.flags.needs_rela = true; |
| 501 | 497 | } |
| 502 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 498 | try symbol.addExtra(.{ .got = index }, elf_file); | |
| 507 | 499 | return index; |
| 508 | 500 | } |
| 509 | 501 | |
| ... | ... | @@ -529,11 +521,7 @@ pub const GotSection = struct { |
| 529 | 521 | const symbol = elf_file.symbol(sym_index); |
| 530 | 522 | symbol.flags.has_tlsgd = true; |
| 531 | 523 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; |
| 532 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 524 | try symbol.addExtra(.{ .tlsgd = index }, elf_file); | |
| 537 | 525 | } |
| 538 | 526 | |
| 539 | 527 | pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| ... | ... | @@ -546,11 +534,7 @@ pub const GotSection = struct { |
| 546 | 534 | const symbol = elf_file.symbol(sym_index); |
| 547 | 535 | symbol.flags.has_gottp = true; |
| 548 | 536 | if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; |
| 549 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 537 | try symbol.addExtra(.{ .gottp = index }, elf_file); | |
| 554 | 538 | } |
| 555 | 539 | |
| 556 | 540 | pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| ... | ... | @@ -563,11 +547,7 @@ pub const GotSection = struct { |
| 563 | 547 | const symbol = elf_file.symbol(sym_index); |
| 564 | 548 | symbol.flags.has_tlsdesc = true; |
| 565 | 549 | got.flags.needs_rela = true; |
| 566 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 550 | try symbol.addExtra(.{ .tlsdesc = index }, elf_file); | |
| 571 | 551 | } |
| 572 | 552 | |
| 573 | 553 | pub fn size(got: GotSection, elf_file: *Elf) usize { |
| ... | ... | @@ -628,8 +608,7 @@ pub const GotSection = struct { |
| 628 | 608 | 0; |
| 629 | 609 | try writeInt(offset, elf_file, writer); |
| 630 | 610 | } else { |
| 631 | const offset = @as(i64, @intCast(symbol.?.address(.{}, elf_file))) - | |
| 632 | @as(i64, @intCast(elf_file.tpAddress())); | |
| 611 | const offset = symbol.?.address(.{}, elf_file) - elf_file.tpAddress(); | |
| 633 | 612 | try writeInt(offset, elf_file, writer); |
| 634 | 613 | } |
| 635 | 614 | }, |
| ... | ... | @@ -640,7 +619,7 @@ pub const GotSection = struct { |
| 640 | 619 | } else { |
| 641 | 620 | try writeInt(0, elf_file, writer); |
| 642 | 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 | 623 | else |
| 645 | 624 | 0; |
| 646 | 625 | try writeInt(offset, elf_file, writer); |
| ... | ... | @@ -666,7 +645,7 @@ pub const GotSection = struct { |
| 666 | 645 | |
| 667 | 646 | switch (entry.tag) { |
| 668 | 647 | .got => { |
| 669 | const offset = symbol.?.gotAddress(elf_file); | |
| 648 | const offset: u64 = @intCast(symbol.?.gotAddress(elf_file)); | |
| 670 | 649 | if (symbol.?.flags.import) { |
| 671 | 650 | elf_file.addRelaDynAssumeCapacity(.{ |
| 672 | 651 | .offset = offset, |
| ... | ... | @@ -679,7 +658,7 @@ pub const GotSection = struct { |
| 679 | 658 | elf_file.addRelaDynAssumeCapacity(.{ |
| 680 | 659 | .offset = offset, |
| 681 | 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 | 663 | continue; |
| 685 | 664 | } |
| ... | ... | @@ -689,14 +668,14 @@ pub const GotSection = struct { |
| 689 | 668 | elf_file.addRelaDynAssumeCapacity(.{ |
| 690 | 669 | .offset = offset, |
| 691 | 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 | 676 | .tlsld => { |
| 698 | 677 | if (is_dyn_lib) { |
| 699 | const offset = entry.address(elf_file); | |
| 678 | const offset: u64 = @intCast(entry.address(elf_file)); | |
| 700 | 679 | elf_file.addRelaDynAssumeCapacity(.{ |
| 701 | 680 | .offset = offset, |
| 702 | 681 | .type = relocation.encode(.dtpmod, cpu_arch), |
| ... | ... | @@ -705,7 +684,7 @@ pub const GotSection = struct { |
| 705 | 684 | }, |
| 706 | 685 | |
| 707 | 686 | .tlsgd => { |
| 708 | const offset = symbol.?.tlsGdAddress(elf_file); | |
| 687 | const offset: u64 = @intCast(symbol.?.tlsGdAddress(elf_file)); | |
| 709 | 688 | if (symbol.?.flags.import) { |
| 710 | 689 | elf_file.addRelaDynAssumeCapacity(.{ |
| 711 | 690 | .offset = offset, |
| ... | ... | @@ -727,7 +706,7 @@ pub const GotSection = struct { |
| 727 | 706 | }, |
| 728 | 707 | |
| 729 | 708 | .gottp => { |
| 730 | const offset = symbol.?.gotTpAddress(elf_file); | |
| 709 | const offset: u64 = @intCast(symbol.?.gotTpAddress(elf_file)); | |
| 731 | 710 | if (symbol.?.flags.import) { |
| 732 | 711 | elf_file.addRelaDynAssumeCapacity(.{ |
| 733 | 712 | .offset = offset, |
| ... | ... | @@ -738,18 +717,18 @@ pub const GotSection = struct { |
| 738 | 717 | elf_file.addRelaDynAssumeCapacity(.{ |
| 739 | 718 | .offset = offset, |
| 740 | 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 | 725 | .tlsdesc => { |
| 747 | const offset = symbol.?.tlsDescAddress(elf_file); | |
| 726 | const offset: u64 = @intCast(symbol.?.tlsDescAddress(elf_file)); | |
| 748 | 727 | elf_file.addRelaDynAssumeCapacity(.{ |
| 749 | 728 | .offset = offset, |
| 750 | 729 | .sym = if (symbol.?.flags.import) extra.?.dynamic else 0, |
| 751 | 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 | 805 | .st_info = elf.STT_OBJECT, |
| 827 | 806 | .st_other = 0, |
| 828 | 807 | .st_shndx = @intCast(elf_file.got_section_index.?), |
| 829 | .st_value = st_value, | |
| 808 | .st_value = @intCast(st_value), | |
| 830 | 809 | .st_size = st_size, |
| 831 | 810 | }; |
| 832 | 811 | } |
| ... | ... | @@ -877,11 +856,7 @@ pub const PltSection = struct { |
| 877 | 856 | const index = @as(u32, @intCast(plt.symbols.items.len)); |
| 878 | 857 | const symbol = elf_file.symbol(sym_index); |
| 879 | 858 | symbol.flags.has_plt = true; |
| 880 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 859 | try symbol.addExtra(.{ .plt = index }, elf_file); | |
| 885 | 860 | try plt.symbols.append(gpa, sym_index); |
| 886 | 861 | } |
| 887 | 862 | |
| ... | ... | @@ -924,7 +899,7 @@ pub const PltSection = struct { |
| 924 | 899 | const sym = elf_file.symbol(sym_index); |
| 925 | 900 | assert(sym.flags.import); |
| 926 | 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 | 903 | const r_sym: u64 = extra.dynamic; |
| 929 | 904 | const r_type = relocation.encode(.jump_slot, cpu_arch); |
| 930 | 905 | elf_file.rela_plt.appendAssumeCapacity(.{ |
| ... | ... | @@ -960,7 +935,7 @@ pub const PltSection = struct { |
| 960 | 935 | .st_info = elf.STT_FUNC, |
| 961 | 936 | .st_other = 0, |
| 962 | 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 | 939 | .st_size = entrySize(cpu_arch), |
| 965 | 940 | }; |
| 966 | 941 | } |
| ... | ... | @@ -1033,13 +1008,13 @@ pub const PltSection = struct { |
| 1033 | 1008 | const aarch64 = struct { |
| 1034 | 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; | |
| 1037 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; | |
| 1011 | const plt_addr: i64 = @intCast(elf_file.shdrs.items[elf_file.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 | 1013 | // TODO: relax if possible |
| 1039 | 1014 | // .got.plt[2] |
| 1040 | 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); | |
| 1042 | const add_off: u12 = @truncate(got_plt_addr + 16); | |
| 1016 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8); | |
| 1017 | const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); | |
| 1043 | 1018 | |
| 1044 | 1019 | const preamble = &[_]Instruction{ |
| 1045 | 1020 | Instruction.stp( |
| ... | ... | @@ -1067,8 +1042,8 @@ pub const PltSection = struct { |
| 1067 | 1042 | const target_addr = sym.gotPltAddress(elf_file); |
| 1068 | 1043 | const source_addr = sym.pltAddress(elf_file); |
| 1069 | 1044 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); |
| 1070 | const ldr_off = try math.divExact(u12, @truncate(target_addr), 8); | |
| 1071 | const add_off: u12 = @truncate(target_addr); | |
| 1045 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); | |
| 1046 | const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); | |
| 1072 | 1047 | const insts = &[_]Instruction{ |
| 1073 | 1048 | Instruction.adrp(.x16, pages), |
| 1074 | 1049 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), |
| ... | ... | @@ -1101,7 +1076,7 @@ pub const GotPltSection = struct { |
| 1101 | 1076 | { |
| 1102 | 1077 | // [0]: _DYNAMIC |
| 1103 | 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 | 1081 | // [1]: 0x0 |
| 1107 | 1082 | // [2]: 0x0 |
| ... | ... | @@ -1132,11 +1107,7 @@ pub const PltGotSection = struct { |
| 1132 | 1107 | const symbol = elf_file.symbol(sym_index); |
| 1133 | 1108 | symbol.flags.has_plt = true; |
| 1134 | 1109 | symbol.flags.has_got = true; |
| 1135 | if (symbol.extra(elf_file)) |extra| { | |
| 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); | |
| 1110 | try symbol.addExtra(.{ .plt_got = index }, elf_file); | |
| 1140 | 1111 | try plt_got.symbols.append(gpa, sym_index); |
| 1141 | 1112 | } |
| 1142 | 1113 | |
| ... | ... | @@ -1181,7 +1152,7 @@ pub const PltGotSection = struct { |
| 1181 | 1152 | .st_info = elf.STT_FUNC, |
| 1182 | 1153 | .st_other = 0, |
| 1183 | 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 | 1156 | .st_size = 16, |
| 1186 | 1157 | }; |
| 1187 | 1158 | } |
| ... | ... | @@ -1212,7 +1183,7 @@ pub const PltGotSection = struct { |
| 1212 | 1183 | const target_addr = sym.gotAddress(elf_file); |
| 1213 | 1184 | const source_addr = sym.pltGotAddress(elf_file); |
| 1214 | 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 | 1187 | const insts = &[_]Instruction{ |
| 1217 | 1188 | Instruction.adrp(.x16, pages), |
| 1218 | 1189 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), |
| ... | ... | @@ -1248,12 +1219,7 @@ pub const CopyRelSection = struct { |
| 1248 | 1219 | symbol.flags.@"export" = true; |
| 1249 | 1220 | symbol.flags.has_copy_rel = true; |
| 1250 | 1221 | symbol.flags.weak = false; |
| 1251 | ||
| 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); | |
| 1222 | try symbol.addExtra(.{ .copy_rel = index }, elf_file); | |
| 1257 | 1223 | try copy_rel.symbols.append(gpa, sym_index); |
| 1258 | 1224 | |
| 1259 | 1225 | const shared_object = symbol.file(elf_file).?.shared_object; |
| ... | ... | @@ -1280,9 +1246,9 @@ pub const CopyRelSection = struct { |
| 1280 | 1246 | const symbol = elf_file.symbol(sym_index); |
| 1281 | 1247 | const shared_object = symbol.file(elf_file).?.shared_object; |
| 1282 | 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 | 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 | 1253 | const aliases = shared_object.symbolAliases(sym_index, elf_file); |
| 1288 | 1254 | for (aliases) |alias| { |
| ... | ... | @@ -1303,7 +1269,7 @@ pub const CopyRelSection = struct { |
| 1303 | 1269 | assert(sym.flags.import and sym.flags.has_copy_rel); |
| 1304 | 1270 | const extra = sym.extra(elf_file).?; |
| 1305 | 1271 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1306 | .offset = sym.address(.{}, elf_file), | |
| 1272 | .offset = @intCast(sym.address(.{}, elf_file)), | |
| 1307 | 1273 | .sym = extra.dynamic, |
| 1308 | 1274 | .type = relocation.encode(.copy, cpu_arch), |
| 1309 | 1275 | }); |
| ... | ... | @@ -1335,11 +1301,7 @@ pub const DynsymSection = struct { |
| 1335 | 1301 | const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); |
| 1336 | 1302 | const sym = elf_file.symbol(sym_index); |
| 1337 | 1303 | sym.flags.has_dynamic = true; |
| 1338 | if (sym.extra(elf_file)) |extra| { | |
| 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); | |
| 1304 | try sym.addExtra(.{ .dynamic = index }, elf_file); | |
| 1343 | 1305 | const off = try elf_file.insertDynString(sym.name(elf_file)); |
| 1344 | 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 | assert(atoms.len > 0); |
| 8 | 8 | |
| 9 | 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 | 13 | var i: usize = 0; |
| ... | ... | @@ -22,7 +22,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { |
| 22 | 22 | const atom_index = atoms[i]; |
| 23 | 23 | const atom = elf_file.atom(atom_index).?; |
| 24 | 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 | 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 | 51 | }; |
| 51 | 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 | 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 | 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 | 65 | const offset = alignment.forward(shdr.sh_size); |
| 64 | 66 | const padding = offset - shdr.sh_size; |
| 65 | 67 | shdr.sh_size += padding + size; |
| 66 | 68 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); |
| 67 | return offset; | |
| 69 | return @intCast(offset); | |
| 68 | 70 | } |
| 69 | 71 | |
| 70 | 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 | 80 | } |
| 79 | 81 | |
| 80 | 82 | pub const Thunk = struct { |
| 81 | value: u64 = 0, | |
| 83 | value: i64 = 0, | |
| 82 | 84 | output_section_index: u32 = 0, |
| 83 | 85 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, |
| 84 | 86 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| ... | ... | @@ -92,14 +94,14 @@ pub const Thunk = struct { |
| 92 | 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 | 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 | 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 | 107 | pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { |
| ... | ... | @@ -131,7 +133,7 @@ pub const Thunk = struct { |
| 131 | 133 | .st_info = elf.STT_FUNC, |
| 132 | 134 | .st_other = 0, |
| 133 | 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 | 137 | .st_size = trampolineSize(cpu_arch), |
| 136 | 138 | }; |
| 137 | 139 | } |
| ... | ... | @@ -204,9 +206,9 @@ const aarch64 = struct { |
| 204 | 206 | if (target.flags.has_plt) return false; |
| 205 | 207 | if (atom.output_section_index != target.output_section_index) return false; |
| 206 | 208 | const target_atom = target.atom(elf_file).?; |
| 207 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | |
| 208 | const saddr = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset)); | |
| 209 | const taddr: i64 = @intCast(target.address(.{}, elf_file)); | |
| 209 | if (target_atom.value == -1) return false; | |
| 210 | const saddr = atom.address(elf_file) + @as(i64, @intCast(rel.r_offset)); | |
| 211 | const taddr = target.address(.{}, elf_file); | |
| 210 | 212 | _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false; |
| 211 | 213 | return true; |
| 212 | 214 | } |
| ... | ... | @@ -214,11 +216,11 @@ const aarch64 = struct { |
| 214 | 216 | fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { |
| 215 | 217 | for (thunk.symbols.keys(), 0..) |sym_index, i| { |
| 216 | 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 | 220 | const taddr = sym.address(.{}, elf_file); |
| 219 | 221 | const pages = try util.calcNumberOfPages(saddr, taddr); |
| 220 | 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 | 224 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); |
| 223 | 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 | 770 | }; |
| 771 | 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 | 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 | 267 | }, |
| 268 | 268 | .aarch64 => { |
| 269 | 269 | // TODO relax if possible |
| 270 | const pages = try aarch64.calcNumberOfPages(source, target); | |
| 270 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); | |
| 271 | 271 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 272 | 272 | const off = try math.divExact(u12, @truncate(target), 8); |
| 273 | 273 | try writer.writeInt( |
| ... | ... | @@ -411,7 +411,7 @@ pub const StubsHelperSection = struct { |
| 411 | 411 | .aarch64 => { |
| 412 | 412 | { |
| 413 | 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 | 415 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); |
| 416 | 416 | const off: u12 = @truncate(dyld_private_addr); |
| 417 | 417 | try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); |
| ... | ... | @@ -424,7 +424,7 @@ pub const StubsHelperSection = struct { |
| 424 | 424 | ).toU32(), .little); |
| 425 | 425 | { |
| 426 | 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 | 428 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 429 | 429 | const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); |
| 430 | 430 | try writer.writeInt(u32, aarch64.Instruction.ldr( |
| ... | ... | @@ -679,7 +679,7 @@ pub const ObjcStubsSection = struct { |
| 679 | 679 | { |
| 680 | 680 | const target = sym.getObjcSelrefsAddress(macho_file); |
| 681 | 681 | const source = addr; |
| 682 | const pages = try aarch64.calcNumberOfPages(source, target); | |
| 682 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); | |
| 683 | 683 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); |
| 684 | 684 | const off = try math.divExact(u12, @truncate(target), 8); |
| 685 | 685 | try writer.writeInt( |
| ... | ... | @@ -692,7 +692,7 @@ pub const ObjcStubsSection = struct { |
| 692 | 692 | const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?); |
| 693 | 693 | const target = target_sym.getGotAddress(macho_file); |
| 694 | 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 | 696 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 697 | 697 | const off = try math.divExact(u12, @truncate(target), 8); |
| 698 | 698 | try writer.writeInt( |
src/link/MachO/thunks.zig+1-1| ... | ... | @@ -99,7 +99,7 @@ pub const Thunk = struct { |
| 99 | 99 | const sym = macho_file.getSymbol(sym_index); |
| 100 | 100 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 101 | 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 | 103 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
| 104 | 104 | const off: u12 = @truncate(taddr); |
| 105 | 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 | 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 | 29 | const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; |
| 30 | 30 | const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; |
| 31 | 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 | 61 | elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target })); |
| 62 | 62 | elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target })); |
| 63 | 63 | elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target })); |
| 64 | elf_step.dependOn(testCommentString(b, .{ .target = musl_target })); | |
| 64 | 65 | elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); |
| 65 | 66 | elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); |
| 66 | 67 | elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); |
| ... | ... | @@ -72,6 +73,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 72 | 73 | elf_step.dependOn(testLinkingC(b, .{ .target = musl_target })); |
| 73 | 74 | elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target })); |
| 74 | 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 | 78 | // https://github.com/ziglang/zig/issues/17451 |
| 76 | 79 | // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target })); |
| 77 | 80 | elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target })); |
| ... | ... | @@ -81,6 +84,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 81 | 84 | elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target })); |
| 82 | 85 | // https://github.com/ziglang/zig/issues/17430 |
| 83 | 86 | // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target })); |
| 87 | elf_step.dependOn(testCommentString(b, .{ .target = gnu_target })); | |
| 84 | 88 | elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target })); |
| 85 | 89 | // https://github.com/ziglang/zig/issues/17430 |
| 86 | 90 | // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target })); |
| ... | ... | @@ -152,6 +156,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 152 | 156 | elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl })); |
| 153 | 157 | |
| 154 | 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 | 161 | elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl })); |
| 156 | 162 | elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl })); |
| 157 | 163 | elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target })); |
| ... | ... | @@ -362,6 +368,36 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step { |
| 362 | 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 | 401 | fn testCommonSymbols(b: *Build, opts: Options) *Step { |
| 366 | 402 | const test_step = addTestStep(b, "common-symbols", opts); |
| 367 | 403 | |
| ... | ... | @@ -2267,6 +2303,125 @@ fn testLinkingZig(b: *Build, opts: Options) *Step { |
| 2267 | 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 | 2425 | fn testNoEhFrameHdr(b: *Build, opts: Options) *Step { |
| 2271 | 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 | 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 | 2713 | fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step { |
| 2532 | 2714 | const test_step = addTestStep(b, "relocatable-no-eh-frame", opts); |
| 2533 | 2715 |
test/link/link.zig-18| ... | ... | @@ -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 | 1 | pub const BuildOptions = struct { |
| 20 | 2 | has_macos_sdk: bool, |
| 21 | 3 | has_ios_sdk: bool, |