authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-04-21 10:37:49+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-23 17:14:03-07:00
logeb5d67b146da7af693bc45f61e69070b0d6b27bb
tree7543827e786486810b5173cb6ece5714b04843b2
parent082e5091af38acd0669f6ca14e13dee1ce65e509

Merge pull request #19714 from ziglang/elf-merge-strings

link/elf: implement string merging

18 files changed, 1368 insertions(+), 343 deletions(-)

src/link/Elf.zig+305-32
...@@ -205,10 +205,19 @@ num_ifunc_dynrelocs: usize = 0,...@@ -205,10 +205,19 @@ num_ifunc_dynrelocs: usize = 0,
205205
206/// List of atoms that are owned directly by the linker.206/// List of atoms that are owned directly by the linker.
207atoms: std.ArrayListUnmanaged(Atom) = .{},207atoms: std.ArrayListUnmanaged(Atom) = .{},
208atoms_extra: std.ArrayListUnmanaged(u32) = .{},
208209
209/// List of range extension thunks.210/// List of range extension thunks.
210thunks: std.ArrayListUnmanaged(Thunk) = .{},211thunks: std.ArrayListUnmanaged(Thunk) = .{},
211212
213/// List of output merge sections with deduped contents.
214merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
215/// List of output merge subsections.
216/// Each subsection is akin to Atom but belongs to a MergeSection.
217merge_subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
218/// List of input merge sections as parsed from input relocatables.
219merge_input_sections: std.ArrayListUnmanaged(InputMergeSection) = .{},
220
212/// Table of last atom index in a section and matching atom free list if any.221/// Table of last atom index in a section and matching atom free list if any.
213last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},222last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
214223
...@@ -369,6 +378,7 @@ pub fn createEmpty(...@@ -369,6 +378,7 @@ pub fn createEmpty(
369 try self.symbols_extra.append(gpa, 0);378 try self.symbols_extra.append(gpa, 0);
370 // Allocate atom index 0 to null atom379 // Allocate atom index 0 to null atom
371 try self.atoms.append(gpa, .{});380 try self.atoms.append(gpa, .{});
381 try self.atoms_extra.append(gpa, 0);
372 // Append null file at index 0382 // Append null file at index 0
373 try self.files.append(gpa, .null);383 try self.files.append(gpa, .null);
374 // Append null byte to string tables384 // Append null byte to string tables
...@@ -378,6 +388,8 @@ pub fn createEmpty(...@@ -378,6 +388,8 @@ pub fn createEmpty(
378 _ = try self.addSection(.{ .name = "" });388 _ = try self.addSection(.{ .name = "" });
379 // Append null symbol in output symtab389 // Append null symbol in output symtab
380 try self.symtab.append(gpa, null_sym);390 try self.symtab.append(gpa, null_sym);
391 // Append null input merge section.
392 try self.merge_input_sections.append(gpa, .{});
381393
382 if (!is_obj_or_ar) {394 if (!is_obj_or_ar) {
383 try self.dynstrtab.append(gpa, 0);395 try self.dynstrtab.append(gpa, 0);
...@@ -491,7 +503,20 @@ pub fn deinit(self: *Elf) void {...@@ -491,7 +503,20 @@ pub fn deinit(self: *Elf) void {
491 self.start_stop_indexes.deinit(gpa);503 self.start_stop_indexes.deinit(gpa);
492504
493 self.atoms.deinit(gpa);505 self.atoms.deinit(gpa);
506 self.atoms_extra.deinit(gpa);
507 for (self.thunks.items) |*th| {
508 th.deinit(gpa);
509 }
494 self.thunks.deinit(gpa);510 self.thunks.deinit(gpa);
511 for (self.merge_sections.items) |*sect| {
512 sect.deinit(gpa);
513 }
514 self.merge_sections.deinit(gpa);
515 self.merge_subsections.deinit(gpa);
516 for (self.merge_input_sections.items) |*sect| {
517 sect.deinit(gpa);
518 }
519 self.merge_input_sections.deinit(gpa);
495 for (self.last_atom_and_free_list_table.values()) |*value| {520 for (self.last_atom_and_free_list_table.values()) |*value| {
496 value.free_list.deinit(gpa);521 value.free_list.deinit(gpa);
497 }522 }
...@@ -1289,6 +1314,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1289,6 +1314,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1289 // symbol for potential resolution at load-time.1314 // symbol for potential resolution at load-time.
1290 self.resolveSymbols();1315 self.resolveSymbols();
1291 self.markEhFrameAtomsDead();1316 self.markEhFrameAtomsDead();
1317 try self.resolveMergeSections();
12921318
1293 try self.convertCommonSymbols();1319 try self.convertCommonSymbols();
1294 self.markImportsExports();1320 self.markImportsExports();
...@@ -1313,7 +1339,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1313,7 +1339,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1313 else => |e| return e,1339 else => |e| return e,
1314 };1340 };
13151341
1342 try self.addCommentString();
1343 try self.finalizeMergeSections();
1316 try self.initOutputSections();1344 try self.initOutputSections();
1345 try self.initMergeSections();
1317 try self.addLinkerDefinedSymbols();1346 try self.addLinkerDefinedSymbols();
1318 self.claimUnresolved();1347 self.claimUnresolved();
13191348
...@@ -1332,6 +1361,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1332,6 +1361,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1332 self.sortDynamicSymtab();1361 self.sortDynamicSymtab();
1333 try self.setHashSections();1362 try self.setHashSections();
1334 try self.setVersionSymtab();1363 try self.setVersionSymtab();
1364 try self.updateMergeSectionSizes();
1335 try self.updateSectionSizes();1365 try self.updateSectionSizes();
13361366
1337 try self.allocatePhdrTable();1367 try self.allocatePhdrTable();
...@@ -1359,7 +1389,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1359,7 +1389,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1359 if (shdr.sh_type == elf.SHT_NOBITS) continue;1389 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1360 const code = try zig_object.codeAlloc(self, atom_index);1390 const code = try zig_object.codeAlloc(self, atom_index);
1361 defer gpa.free(code);1391 defer gpa.free(code);
1362 const file_offset = shdr.sh_offset + atom_ptr.value;1392 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1363 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {1393 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
1364 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,1394 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
1365 error.UnsupportedCpuArch => {1395 error.UnsupportedCpuArch => {
...@@ -1377,6 +1407,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1377,6 +1407,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1377 try self.writePhdrTable();1407 try self.writePhdrTable();
1378 try self.writeShdrTable();1408 try self.writeShdrTable();
1379 try self.writeAtoms();1409 try self.writeAtoms();
1410 try self.writeMergeSections();
1380 self.writeSyntheticSections() catch |err| switch (err) {1411 self.writeSyntheticSections() catch |err| switch (err) {
1381 error.RelocFailure => return error.FlushFailure,1412 error.RelocFailure => return error.FlushFailure,
1382 error.UnsupportedCpuArch => {1413 error.UnsupportedCpuArch => {
...@@ -2946,7 +2977,10 @@ pub fn writeElfHeader(self: *Elf) !void {...@@ -2946,7 +2977,10 @@ pub fn writeElfHeader(self: *Elf) !void {
2946 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);2977 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
2947 index += 4;2978 index += 4;
29482979
2949 const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).address(.{}, self) else 0;2980 const e_entry = if (self.entry_index) |entry_index|
2981 @as(u64, @intCast(self.symbol(entry_index).address(.{}, self)))
2982 else
2983 0;
2950 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;2984 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
2951 switch (self.ptr_width) {2985 switch (self.ptr_width) {
2952 .p32 => {2986 .p32 => {
...@@ -3132,14 +3166,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3132,14 +3166,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3132 if (self.dynamic_section_index) |shndx| {3166 if (self.dynamic_section_index) |shndx| {
3133 const shdr = &self.shdrs.items[shndx];3167 const shdr = &self.shdrs.items[shndx];
3134 const symbol_ptr = self.symbol(self.dynamic_index.?);3168 const symbol_ptr = self.symbol(self.dynamic_index.?);
3135 symbol_ptr.value = shdr.sh_addr;3169 symbol_ptr.value = @intCast(shdr.sh_addr);
3136 symbol_ptr.output_section_index = shndx;3170 symbol_ptr.output_section_index = shndx;
3137 }3171 }
31383172
3139 // __ehdr_start3173 // __ehdr_start
3140 {3174 {
3141 const symbol_ptr = self.symbol(self.ehdr_start_index.?);3175 const symbol_ptr = self.symbol(self.ehdr_start_index.?);
3142 symbol_ptr.value = self.image_base;3176 symbol_ptr.value = @intCast(self.image_base);
3143 symbol_ptr.output_section_index = 1;3177 symbol_ptr.output_section_index = 1;
3144 }3178 }
31453179
...@@ -3149,9 +3183,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3149,9 +3183,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3149 const end_sym = self.symbol(self.init_array_end_index.?);3183 const end_sym = self.symbol(self.init_array_end_index.?);
3150 const shdr = &self.shdrs.items[shndx];3184 const shdr = &self.shdrs.items[shndx];
3151 start_sym.output_section_index = shndx;3185 start_sym.output_section_index = shndx;
3152 start_sym.value = shdr.sh_addr;3186 start_sym.value = @intCast(shdr.sh_addr);
3153 end_sym.output_section_index = shndx;3187 end_sym.output_section_index = shndx;
3154 end_sym.value = shdr.sh_addr + shdr.sh_size;3188 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3155 }3189 }
31563190
3157 // __fini_array_start, __fini_array_end3191 // __fini_array_start, __fini_array_end
...@@ -3160,9 +3194,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3160,9 +3194,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3160 const end_sym = self.symbol(self.fini_array_end_index.?);3194 const end_sym = self.symbol(self.fini_array_end_index.?);
3161 const shdr = &self.shdrs.items[shndx];3195 const shdr = &self.shdrs.items[shndx];
3162 start_sym.output_section_index = shndx;3196 start_sym.output_section_index = shndx;
3163 start_sym.value = shdr.sh_addr;3197 start_sym.value = @intCast(shdr.sh_addr);
3164 end_sym.output_section_index = shndx;3198 end_sym.output_section_index = shndx;
3165 end_sym.value = shdr.sh_addr + shdr.sh_size;3199 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3166 }3200 }
31673201
3168 // __preinit_array_start, __preinit_array_end3202 // __preinit_array_start, __preinit_array_end
...@@ -3171,9 +3205,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3171,9 +3205,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3171 const end_sym = self.symbol(self.preinit_array_end_index.?);3205 const end_sym = self.symbol(self.preinit_array_end_index.?);
3172 const shdr = &self.shdrs.items[shndx];3206 const shdr = &self.shdrs.items[shndx];
3173 start_sym.output_section_index = shndx;3207 start_sym.output_section_index = shndx;
3174 start_sym.value = shdr.sh_addr;3208 start_sym.value = @intCast(shdr.sh_addr);
3175 end_sym.output_section_index = shndx;3209 end_sym.output_section_index = shndx;
3176 end_sym.value = shdr.sh_addr + shdr.sh_size;3210 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3177 }3211 }
31783212
3179 // _GLOBAL_OFFSET_TABLE_3213 // _GLOBAL_OFFSET_TABLE_
...@@ -3181,14 +3215,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3181,14 +3215,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3181 if (self.got_plt_section_index) |shndx| {3215 if (self.got_plt_section_index) |shndx| {
3182 const shdr = self.shdrs.items[shndx];3216 const shdr = self.shdrs.items[shndx];
3183 const sym = self.symbol(self.got_index.?);3217 const sym = self.symbol(self.got_index.?);
3184 sym.value = shdr.sh_addr;3218 sym.value = @intCast(shdr.sh_addr);
3185 sym.output_section_index = shndx;3219 sym.output_section_index = shndx;
3186 }3220 }
3187 } else {3221 } else {
3188 if (self.got_section_index) |shndx| {3222 if (self.got_section_index) |shndx| {
3189 const shdr = self.shdrs.items[shndx];3223 const shdr = self.shdrs.items[shndx];
3190 const sym = self.symbol(self.got_index.?);3224 const sym = self.symbol(self.got_index.?);
3191 sym.value = shdr.sh_addr;3225 sym.value = @intCast(shdr.sh_addr);
3192 sym.output_section_index = shndx;3226 sym.output_section_index = shndx;
3193 }3227 }
3194 }3228 }
...@@ -3197,7 +3231,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3197,7 +3231,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3197 if (self.plt_section_index) |shndx| {3231 if (self.plt_section_index) |shndx| {
3198 const shdr = &self.shdrs.items[shndx];3232 const shdr = &self.shdrs.items[shndx];
3199 const symbol_ptr = self.symbol(self.plt_index.?);3233 const symbol_ptr = self.symbol(self.plt_index.?);
3200 symbol_ptr.value = shdr.sh_addr;3234 symbol_ptr.value = @intCast(shdr.sh_addr);
3201 symbol_ptr.output_section_index = shndx;3235 symbol_ptr.output_section_index = shndx;
3202 }3236 }
32033237
...@@ -3205,7 +3239,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3205,7 +3239,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3205 if (self.dso_handle_index) |index| {3239 if (self.dso_handle_index) |index| {
3206 const shdr = &self.shdrs.items[1];3240 const shdr = &self.shdrs.items[1];
3207 const symbol_ptr = self.symbol(index);3241 const symbol_ptr = self.symbol(index);
3208 symbol_ptr.value = shdr.sh_addr;3242 symbol_ptr.value = @intCast(shdr.sh_addr);
3209 symbol_ptr.output_section_index = 0;3243 symbol_ptr.output_section_index = 0;
3210 }3244 }
32113245
...@@ -3213,7 +3247,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3213,7 +3247,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3213 if (self.eh_frame_hdr_section_index) |shndx| {3247 if (self.eh_frame_hdr_section_index) |shndx| {
3214 const shdr = &self.shdrs.items[shndx];3248 const shdr = &self.shdrs.items[shndx];
3215 const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);3249 const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);
3216 symbol_ptr.value = shdr.sh_addr;3250 symbol_ptr.value = @intCast(shdr.sh_addr);
3217 symbol_ptr.output_section_index = shndx;3251 symbol_ptr.output_section_index = shndx;
3218 }3252 }
32193253
...@@ -3225,9 +3259,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3225,9 +3259,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3225 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);3259 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
3226 const start_sym = self.symbol(self.rela_iplt_start_index.?);3260 const start_sym = self.symbol(self.rela_iplt_start_index.?);
3227 const end_sym = self.symbol(self.rela_iplt_end_index.?);3261 const end_sym = self.symbol(self.rela_iplt_end_index.?);
3228 start_sym.value = start_addr;3262 start_sym.value = @intCast(start_addr);
3229 start_sym.output_section_index = shndx;3263 start_sym.output_section_index = shndx;
3230 end_sym.value = end_addr;3264 end_sym.value = @intCast(end_addr);
3231 end_sym.output_section_index = shndx;3265 end_sym.output_section_index = shndx;
3232 }3266 }
32333267
...@@ -3236,7 +3270,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3236,7 +3270,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3236 const end_symbol = self.symbol(self.end_index.?);3270 const end_symbol = self.symbol(self.end_index.?);
3237 for (self.shdrs.items, 0..) |shdr, shndx| {3271 for (self.shdrs.items, 0..) |shdr, shndx| {
3238 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {3272 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
3239 end_symbol.value = shdr.sh_addr + shdr.sh_size;3273 end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);
3240 end_symbol.output_section_index = @intCast(shndx);3274 end_symbol.output_section_index = @intCast(shndx);
3241 }3275 }
3242 }3276 }
...@@ -3251,9 +3285,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3251,9 +3285,9 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3251 const stop = self.symbol(self.start_stop_indexes.items[index + 1]);3285 const stop = self.symbol(self.start_stop_indexes.items[index + 1]);
3252 const shndx = self.sectionByName(name["__start_".len..]).?;3286 const shndx = self.sectionByName(name["__start_".len..]).?;
3253 const shdr = &self.shdrs.items[shndx];3287 const shdr = &self.shdrs.items[shndx];
3254 start.value = shdr.sh_addr;3288 start.value = @intCast(shdr.sh_addr);
3255 start.output_section_index = shndx;3289 start.output_section_index = shndx;
3256 stop.value = shdr.sh_addr + shdr.sh_size;3290 stop.value = @intCast(shdr.sh_addr + shdr.sh_size);
3257 stop.output_section_index = shndx;3291 stop.output_section_index = shndx;
3258 }3292 }
3259 }3293 }
...@@ -3263,7 +3297,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3263,7 +3297,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3263 const sym = self.symbol(index);3297 const sym = self.symbol(index);
3264 if (self.sectionByName(".sdata")) |shndx| {3298 if (self.sectionByName(".sdata")) |shndx| {
3265 const shdr = self.shdrs.items[shndx];3299 const shdr = self.shdrs.items[shndx];
3266 sym.value = shdr.sh_addr + 0x800;3300 sym.value = @intCast(shdr.sh_addr + 0x800);
3267 sym.output_section_index = shndx;3301 sym.output_section_index = shndx;
3268 } else {3302 } else {
3269 sym.value = 0;3303 sym.value = 0;
...@@ -3293,12 +3327,122 @@ fn checkDuplicates(self: *Elf) !void {...@@ -3293,12 +3327,122 @@ fn checkDuplicates(self: *Elf) !void {
3293 try self.reportDuplicates(dupes);3327 try self.reportDuplicates(dupes);
3294}3328}
32953329
3330pub 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
3346pub 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
3374pub fn finalizeMergeSections(self: *Elf) !void {
3375 for (self.merge_sections.items) |*msec| {
3376 try msec.finalize(self);
3377 }
3378}
3379
3380pub 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
3395pub 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
3296fn initOutputSections(self: *Elf) !void {3419fn initOutputSections(self: *Elf) !void {
3297 for (self.objects.items) |index| {3420 for (self.objects.items) |index| {
3298 try self.file(index).?.object.initOutputSections(self);3421 try self.file(index).?.object.initOutputSections(self);
3299 }3422 }
3300}3423}
33013424
3425pub 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
3302fn initSyntheticSections(self: *Elf) !void {3446fn initSyntheticSections(self: *Elf) !void {
3303 const comp = self.base.comp;3447 const comp = self.base.comp;
3304 const target = comp.root_mod.resolved_target.result;3448 const target = comp.root_mod.resolved_target.result;
...@@ -3965,6 +4109,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {...@@ -3965,6 +4109,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
3965 }4109 }
3966 }4110 }
39674111
4112 for (self.merge_sections.items) |*msec| {
4113 msec.output_section_index = backlinks[msec.output_section_index];
4114 }
4115
3968 {4116 {
3969 var output_rela_sections = try self.output_rela_sections.clone(gpa);4117 var output_rela_sections = try self.output_rela_sections.clone(gpa);
3970 defer output_rela_sections.deinit(gpa);4118 defer output_rela_sections.deinit(gpa);
...@@ -4052,7 +4200,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4052,7 +4200,7 @@ fn updateSectionSizes(self: *Elf) !void {
4052 if (!atom_ptr.flags.alive) continue;4200 if (!atom_ptr.flags.alive) continue;
4053 const offset = atom_ptr.alignment.forward(shdr.sh_size);4201 const offset = atom_ptr.alignment.forward(shdr.sh_size);
4054 const padding = offset - shdr.sh_size;4202 const padding = offset - shdr.sh_size;
4055 atom_ptr.value = offset;4203 atom_ptr.value = @intCast(offset);
4056 shdr.sh_size += padding + atom_ptr.size;4204 shdr.sh_size += padding + atom_ptr.size;
4057 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);4205 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
4058 }4206 }
...@@ -4535,7 +4683,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4535,7 +4683,7 @@ fn writeAtoms(self: *Elf) !void {
4535 const atom_ptr = self.atom(atom_index).?;4683 const atom_ptr = self.atom(atom_index).?;
4536 assert(atom_ptr.flags.alive);4684 assert(atom_ptr.flags.alive);
45374685
4538 const offset = math.cast(usize, atom_ptr.value - base_offset) orelse4686 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
4539 return error.Overflow;4687 return error.Overflow;
4540 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;4688 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
45414689
...@@ -4576,7 +4724,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4576,7 +4724,7 @@ fn writeAtoms(self: *Elf) !void {
4576 const thunk_size = th.size(self);4724 const thunk_size = th.size(self);
4577 try buffer.ensureUnusedCapacity(thunk_size);4725 try buffer.ensureUnusedCapacity(thunk_size);
4578 const shdr = self.shdrs.items[th.output_section_index];4726 const shdr = self.shdrs.items[th.output_section_index];
4579 const offset = th.value + shdr.sh_offset;4727 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
4580 try th.write(self, buffer.writer());4728 try th.write(self, buffer.writer());
4581 assert(buffer.items.len == thunk_size);4729 assert(buffer.items.len == thunk_size);
4582 try self.base.file.?.pwriteAll(buffer.items, offset);4730 try self.base.file.?.pwriteAll(buffer.items, offset);
...@@ -4611,6 +4759,7 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4611,6 +4759,7 @@ pub fn updateSymtabSize(self: *Elf) !void {
4611 if (self.eh_frame_section_index) |_| {4759 if (self.eh_frame_section_index) |_| {
4612 nlocals += 1;4760 nlocals += 1;
4613 }4761 }
4762 nlocals += @intCast(self.merge_sections.items.len);
46144763
4615 if (self.requiresThunks()) for (self.thunks.items) |*th| {4764 if (self.requiresThunks()) for (self.thunks.items) |*th| {
4616 th.output_symtab_ctx.ilocal = nlocals + 1;4765 th.output_symtab_ctx.ilocal = nlocals + 1;
...@@ -4947,12 +5096,30 @@ fn writeSectionSymbols(self: *Elf) void {...@@ -4947,12 +5096,30 @@ fn writeSectionSymbols(self: *Elf) void {
4947 };5096 };
4948 ilocal += 1;5097 ilocal += 1;
4949 }5098 }
5099
5100 for (self.merge_sections.items) |msec| {
5101 const shdr = self.shdrs.items[msec.output_section_index];
5102 const out_sym = &self.symtab.items[ilocal];
5103 out_sym.* = .{
5104 .st_name = 0,
5105 .st_value = shdr.sh_addr,
5106 .st_info = elf.STT_SECTION,
5107 .st_shndx = @intCast(msec.output_section_index),
5108 .st_size = 0,
5109 .st_other = 0,
5110 };
5111 ilocal += 1;
5112 }
4950}5113}
49515114
4952pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {5115pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
4953 if (self.eh_frame_section_index) |index| {5116 if (self.eh_frame_section_index) |index| {
4954 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);5117 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
4955 }5118 }
5119 const base: usize = if (self.eh_frame_section_index == null) 0 else 1;
5120 for (self.merge_sections.items, 0..) |msec, index| {
5121 if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base);
5122 }
4956 return @intCast(self.output_sections.getIndex(shndx).? + 1);5123 return @intCast(self.output_sections.getIndex(shndx).? + 1);
4957}5124}
49585125
...@@ -5458,6 +5625,50 @@ pub fn addAtom(self: *Elf) !Atom.Index {...@@ -5458,6 +5625,50 @@ pub fn addAtom(self: *Elf) !Atom.Index {
5458 return index;5625 return index;
5459}5626}
54605627
5628pub 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
5634pub 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
5646pub 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
5661pub 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
5461pub fn addThunk(self: *Elf) !Thunk.Index {5672pub fn addThunk(self: *Elf) !Thunk.Index {
5462 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));5673 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
5463 const th = try self.thunks.addOne(self.base.comp.gpa);5674 const th = try self.thunks.addOne(self.base.comp.gpa);
...@@ -5637,35 +5848,88 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO...@@ -5637,35 +5848,88 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO
5637 return &self.comdat_groups_owners.items[index];5848 return &self.comdat_groups_owners.items[index];
5638}5849}
56395850
5640pub fn gotAddress(self: *Elf) u64 {5851pub 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
5858pub fn inputMergeSection(self: *Elf, index: InputMergeSection.Index) ?*InputMergeSection {
5859 if (index == 0) return null;
5860 return &self.merge_input_sections.items[index];
5861}
5862
5863pub 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
5870pub 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
5875pub 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
5898pub 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
5903pub fn gotAddress(self: *Elf) i64 {
5641 const shndx = blk: {5904 const shndx = blk: {
5642 if (self.getTarget().cpu.arch == .x86_64 and self.got_plt_section_index != null)5905 if (self.getTarget().cpu.arch == .x86_64 and self.got_plt_section_index != null)
5643 break :blk self.got_plt_section_index.?;5906 break :blk self.got_plt_section_index.?;
5644 break :blk if (self.got_section_index) |shndx| shndx else null;5907 break :blk if (self.got_section_index) |shndx| shndx else null;
5645 };5908 };
5646 return if (shndx) |index| self.shdrs.items[index].sh_addr else 0;5909 return if (shndx) |index| @intCast(self.shdrs.items[index].sh_addr) else 0;
5647}5910}
56485911
5649pub fn tpAddress(self: *Elf) u64 {5912pub fn tpAddress(self: *Elf) i64 {
5650 const index = self.phdr_tls_index orelse return 0;5913 const index = self.phdr_tls_index orelse return 0;
5651 const phdr = self.phdrs.items[index];5914 const phdr = self.phdrs.items[index];
5652 return switch (self.getTarget().cpu.arch) {5915 const addr = switch (self.getTarget().cpu.arch) {
5653 .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align),5916 .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align),
5654 .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align),5917 .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align),
5655 else => @panic("TODO implement getTpAddress for this arch"),5918 else => @panic("TODO implement getTpAddress for this arch"),
5656 };5919 };
5920 return @intCast(addr);
5657}5921}
56585922
5659pub fn dtpAddress(self: *Elf) u64 {5923pub fn dtpAddress(self: *Elf) i64 {
5660 const index = self.phdr_tls_index orelse return 0;5924 const index = self.phdr_tls_index orelse return 0;
5661 const phdr = self.phdrs.items[index];5925 const phdr = self.phdrs.items[index];
5662 return phdr.p_vaddr;5926 return @intCast(phdr.p_vaddr);
5663}5927}
56645928
5665pub fn tlsAddress(self: *Elf) u64 {5929pub fn tlsAddress(self: *Elf) i64 {
5666 const index = self.phdr_tls_index orelse return 0;5930 const index = self.phdr_tls_index orelse return 0;
5667 const phdr = self.phdrs.items[index];5931 const phdr = self.phdrs.items[index];
5668 return phdr.p_vaddr;5932 return @intCast(phdr.p_vaddr);
5669}5933}
56705934
5671const ErrorWithNotes = struct {5935const ErrorWithNotes = struct {
...@@ -6043,6 +6307,11 @@ fn fmtDumpState(...@@ -6043,6 +6307,11 @@ fn fmtDumpState(
6043 try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index });6307 try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index });
6044 }6308 }
60456309
6310 try writer.writeAll("\nOutput merge sections\n");
6311 for (self.merge_sections.items) |msec| {
6312 try writer.print(" shdr({d}) : {}\n", .{ msec.output_section_index, msec.fmt(self) });
6313 }
6314
6046 try writer.writeAll("\nOutput shdrs\n");6315 try writer.writeAll("\nOutput shdrs\n");
6047 for (self.shdrs.items, 0..) |shdr, shndx| {6316 for (self.shdrs.items, 0..) |shdr, shndx| {
6048 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{6317 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
...@@ -6235,6 +6504,7 @@ const gc = @import("Elf/gc.zig");...@@ -6235,6 +6504,7 @@ const gc = @import("Elf/gc.zig");
6235const glibc = @import("../glibc.zig");6504const glibc = @import("../glibc.zig");
6236const link = @import("../link.zig");6505const link = @import("../link.zig");
6237const lldMain = @import("../main.zig").lldMain;6506const lldMain = @import("../main.zig").lldMain;
6507const merge_section = @import("Elf/merge_section.zig");
6238const musl = @import("../musl.zig");6508const musl = @import("../musl.zig");
6239const relocatable = @import("Elf/relocatable.zig");6509const relocatable = @import("Elf/relocatable.zig");
6240const relocation = @import("Elf/relocation.zig");6510const relocation = @import("Elf/relocation.zig");
...@@ -6260,10 +6530,13 @@ const GnuHashSection = synthetic_sections.GnuHashSection;...@@ -6260,10 +6530,13 @@ const GnuHashSection = synthetic_sections.GnuHashSection;
6260const GotSection = synthetic_sections.GotSection;6530const GotSection = synthetic_sections.GotSection;
6261const GotPltSection = synthetic_sections.GotPltSection;6531const GotPltSection = synthetic_sections.GotPltSection;
6262const HashSection = synthetic_sections.HashSection;6532const HashSection = synthetic_sections.HashSection;
6533const InputMergeSection = merge_section.InputMergeSection;
6263const LdScript = @import("Elf/LdScript.zig");6534const LdScript = @import("Elf/LdScript.zig");
6264const LinkerDefined = @import("Elf/LinkerDefined.zig");6535const LinkerDefined = @import("Elf/LinkerDefined.zig");
6265const Liveness = @import("../Liveness.zig");6536const Liveness = @import("../Liveness.zig");
6266const LlvmObject = @import("../codegen/llvm.zig").Object;6537const LlvmObject = @import("../codegen/llvm.zig").Object;
6538const MergeSection = merge_section.MergeSection;
6539const MergeSubsection = merge_section.MergeSubsection;
6267const Module = @import("../Module.zig");6540const Module = @import("../Module.zig");
6268const Object = @import("Elf/Object.zig");6541const Object = @import("Elf/Object.zig");
6269const InternPool = @import("../InternPool.zig");6542const InternPool = @import("../InternPool.zig");
src/link/Elf/Atom.zig+187-114
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1/// Address allocated for this Atom.1/// Address allocated for this Atom.
2value: u64 = 0,2value: i64 = 0,
33
4/// Name of this Atom.4/// Name of this Atom.
5name_offset: u32 = 0,5name_offset: u32 = 0,
...@@ -22,32 +22,19 @@ output_section_index: u32 = 0,...@@ -22,32 +22,19 @@ output_section_index: u32 = 0,
22/// Index of the input section containing this atom's relocs.22/// Index of the input section containing this atom's relocs.
23relocs_section_index: u32 = 0,23relocs_section_index: u32 = 0,
2424
25/// Start index of the relocations belonging to this atom.
26rel_index: u32 = 0,
27
28/// Number of relocations belonging to this atom.
29rel_num: u32 = 0,
30
31/// Index of this atom in the linker's atoms table.25/// Index of this atom in the linker's atoms table.
32atom_index: Index = 0,26atom_index: Index = 0,
3327
34/// Index of the thunk for this atom.
35thunk_index: Thunk.Index = 0,
36
37/// Flags we use for state tracking.
38flags: Flags = .{},
39
40/// Start index of FDEs referencing this atom.
41fde_start: u32 = 0,
42
43/// End index of FDEs referencing this atom.
44fde_end: u32 = 0,
45
46/// Points to the previous and next neighbors, based on the `text_offset`.28/// Points to the previous and next neighbors, based on the `text_offset`.
47/// This can be used to find, for example, the capacity of this `TextBlock`.29/// This can be used to find, for example, the capacity of this `TextBlock`.
48prev_index: Index = 0,30prev_index: Index = 0,
49next_index: Index = 0,31next_index: Index = 0,
5032
33/// Flags we use for state tracking.
34flags: Flags = .{},
35
36extra_index: u32 = 0,
37
51pub const Alignment = @import("../../InternPool.zig").Alignment;38pub const Alignment = @import("../../InternPool.zig").Alignment;
5239
53pub fn name(self: Atom, elf_file: *Elf) []const u8 {40pub fn name(self: Atom, elf_file: *Elf) []const u8 {
...@@ -57,10 +44,22 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {...@@ -57,10 +44,22 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
57 };44 };
58}45}
5946
60pub fn address(self: Atom, elf_file: *Elf) u64 {47pub fn address(self: Atom, elf_file: *Elf) i64 {
61 const shndx = self.outputShndx() orelse return self.value;48 const shndx = self.outputShndx() orelse return self.value;
62 const shdr = elf_file.shdrs.items[shndx];49 const shdr = elf_file.shdrs.items[shndx];
63 return shdr.sh_addr + self.value;50 return @as(i64, @intCast(shdr.sh_addr)) + self.value;
51}
52
53pub 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}
6564
66pub fn file(self: Atom, elf_file: *Elf) ?File {65pub fn file(self: Atom, elf_file: *Elf) ?File {
...@@ -68,7 +67,9 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {...@@ -68,7 +67,9 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
68}67}
6968
70pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {69pub 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}
7374
74pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {75pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
...@@ -102,13 +103,13 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {...@@ -102,13 +103,13 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
102 next.address(elf_file)103 next.address(elf_file)
103 else104 else
104 std.math.maxInt(u32);105 std.math.maxInt(u32);
105 return next_addr - self.address(elf_file);106 return @intCast(next_addr - self.address(elf_file));
106}107}
107108
108pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {109pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
109 // No need to keep a free list node for the last block.110 // No need to keep a free list node for the last block.
110 const next = elf_file.atom(self.next_index) orelse return false;111 const next = elf_file.atom(self.next_index) orelse return false;
111 const cap = next.address(elf_file) - self.address(elf_file);112 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
112 const ideal_cap = Elf.padToIdeal(self.size);113 const ideal_cap = Elf.padToIdeal(self.size);
113 if (cap <= ideal_cap) return false;114 if (cap <= ideal_cap) return false;
114 const surplus = cap - ideal_cap;115 const surplus = cap - ideal_cap;
...@@ -141,8 +142,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -141,8 +142,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
141 // Is it enough that we could fit this new atom?142 // Is it enough that we could fit this new atom?
142 const cap = big_atom.capacity(elf_file);143 const cap = big_atom.capacity(elf_file);
143 const ideal_capacity = Elf.padToIdeal(cap);144 const ideal_capacity = Elf.padToIdeal(cap);
144 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;145 const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity;
145 const capacity_end_vaddr = big_atom.value + cap;146 const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap;
146 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
147 const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned);148 const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned);
148 if (new_start_vaddr < ideal_capacity_end_vaddr) {149 if (new_start_vaddr < ideal_capacity_end_vaddr) {
...@@ -167,14 +168,14 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -167,14 +168,14 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
167 if (!keep_free_list_node) {168 if (!keep_free_list_node) {
168 free_list_removal = i;169 free_list_removal = i;
169 }170 }
170 break :blk new_start_vaddr;171 break :blk @intCast(new_start_vaddr);
171 } else if (elf_file.atom(last_atom_index.*)) |last| {172 } else if (elf_file.atom(last_atom_index.*)) |last| {
172 const ideal_capacity = Elf.padToIdeal(last.size);173 const ideal_capacity = Elf.padToIdeal(last.size);
173 const ideal_capacity_end_vaddr = last.value + ideal_capacity;174 const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;
174 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);175 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
175 // Set up the metadata to be updated, after errors are no longer possible.176 // Set up the metadata to be updated, after errors are no longer possible.
176 atom_placement = last.atom_index;177 atom_placement = last.atom_index;
177 break :blk new_start_vaddr;178 break :blk @intCast(new_start_vaddr);
178 } else {179 } else {
179 break :blk 0;180 break :blk 0;
180 }181 }
...@@ -184,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -184,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
184 self.atom_index,185 self.atom_index,
185 self.name(elf_file),186 self.name(elf_file),
186 self.address(elf_file),187 self.address(elf_file),
187 self.address(elf_file) + self.size,188 self.address(elf_file) + @as(i64, @intCast(self.size)),
188 });189 });
189190
190 const expand_section = if (atom_placement) |placement_index|191 const expand_section = if (atom_placement) |placement_index|
...@@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
192 else193 else
193 true;194 true;
194 if (expand_section) {195 if (expand_section) {
195 const needed_size = self.value + self.size;196 const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size)));
196 try elf_file.growAllocSection(self.outputShndx().?, needed_size);197 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
197 last_atom_index.* = self.atom_index;198 last_atom_index.* = self.atom_index;
198199
...@@ -242,7 +243,7 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {...@@ -242,7 +243,7 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {
242}243}
243244
244pub fn grow(self: *Atom, elf_file: *Elf) !void {245pub fn grow(self: *Atom, elf_file: *Elf) !void {
245 if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file))246 if (!self.alignment.check(@intCast(self.value)) or self.size > self.capacity(elf_file))
246 try self.allocate(elf_file);247 try self.allocate(elf_file);
247}248}
248249
...@@ -309,11 +310,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -309,11 +310,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
309310
310pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {311pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
311 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};312 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
312 return switch (self.file(elf_file).?) {313 switch (self.file(elf_file).?) {
313 .zig_object => |x| x.relocs.items[shndx].items,314 .zig_object => |x| return x.relocs.items[shndx].items,
314 .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num],315 .object => |x| {
316 const extras = self.extra(elf_file).?;
317 return x.relocs.items[extras.rel_index..][0..extras.rel_count];
318 },
315 else => unreachable,319 else => unreachable,
316 };320 }
317}321}
318322
319pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {323pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
...@@ -329,11 +333,14 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El...@@ -329,11 +333,14 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
329 };333 };
330 const target = elf_file.symbol(target_index);334 const target = elf_file.symbol(target_index);
331 const r_type = rel.r_type();335 const r_type = rel.r_type();
332 const r_offset = self.value + rel.r_offset;336 const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset)));
333 var r_addend = rel.r_addend;337 var r_addend = rel.r_addend;
334 var r_sym: u32 = 0;338 var r_sym: u32 = 0;
335 switch (target.type(elf_file)) {339 switch (target.type(elf_file)) {
336 elf.STT_SECTION => {340 elf.STT_SECTION => if (target.mergeSubsection(elf_file)) |msub| {
341 r_addend += @intCast(target.address(.{}, elf_file));
342 r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);
343 } else {
337 r_addend += @intCast(target.address(.{}, elf_file));344 r_addend += @intCast(target.address(.{}, elf_file));
338 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);345 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
339 },346 },
...@@ -359,9 +366,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El...@@ -359,9 +366,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
359}366}
360367
361pub fn fdes(self: Atom, elf_file: *Elf) []Fde {368pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
362 if (self.fde_start == self.fde_end) return &[0]Fde{};369 if (!self.flags.fde) return &[0]Fde{};
370 const extras = self.extra(elf_file).?;
363 const object = self.file(elf_file).?.object;371 const object = self.file(elf_file).?.object;
364 return object.fdes.items[self.fde_start..self.fde_end];372 return object.fdes.items[extras.fde_start..][0..extras.fde_count];
365}373}
366374
367pub fn markFdesDead(self: Atom, elf_file: *Elf) void {375pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
...@@ -419,6 +427,12 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -419,6 +427,12 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
419 };427 };
420 const symbol = elf_file.symbol(symbol_index);428 const symbol = elf_file.symbol(symbol_index);
421429
430 const is_synthetic_symbol = switch (file_ptr) {
431 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject
432 .object => |x| rel.r_sym() >= x.symtab.items.len,
433 else => unreachable,
434 };
435
422 // Check for violation of One Definition Rule for COMDATs.436 // Check for violation of One Definition Rule for COMDATs.
423 if (symbol.file(elf_file) == null) {437 if (symbol.file(elf_file) == null) {
424 // TODO convert into an error438 // TODO convert into an error
...@@ -431,7 +445,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -431,7 +445,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
431 }445 }
432446
433 // Report an undefined symbol.447 // Report an undefined symbol.
434 if (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)) continue;448 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)))
449 continue;
435450
436 if (symbol.isIFunc(elf_file)) {451 if (symbol.isIFunc(elf_file)) {
437 symbol.flags.needs_got = true;452 symbol.flags.needs_got = true;
...@@ -743,21 +758,21 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -743,21 +758,21 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
743 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/758 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
744 //759 //
745 // Address of the source atom.760 // Address of the source atom.
746 const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));761 const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));
747 // Addend from the relocation.762 // Addend from the relocation.
748 const A = rel.r_addend;763 const A = rel.r_addend;
749 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.764 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
750 const S = @as(i64, @intCast(target.address(.{}, elf_file)));765 const S = target.address(.{}, elf_file);
751 // Address of the global offset table.766 // Address of the global offset table.
752 const GOT = @as(i64, @intCast(elf_file.gotAddress()));767 const GOT = elf_file.gotAddress();
753 // Address of the .zig.got table entry if any.768 // Address of the .zig.got table entry if any.
754 const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file)));769 const ZIG_GOT = target.zigGotAddress(elf_file);
755 // Relative offset to the start of the global offset table.770 // Relative offset to the start of the global offset table.
756 const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;771 const G = target.gotAddress(elf_file) - GOT;
757 // // Address of the thread pointer.772 // // Address of the thread pointer.
758 const TP = @as(i64, @intCast(elf_file.tpAddress()));773 const TP = elf_file.tpAddress();
759 // Address of the dynamic thread pointer.774 // Address of the dynamic thread pointer.
760 const DTP = @as(i64, @intCast(elf_file.dtpAddress()));775 const DTP = elf_file.dtpAddress();
761776
762 relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{777 relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
763 relocation.fmtRelocType(rel.r_type(), cpu_arch),778 relocation.fmtRelocType(rel.r_type(), cpu_arch),
...@@ -814,9 +829,9 @@ fn resolveDynAbsReloc(...@@ -814,9 +829,9 @@ fn resolveDynAbsReloc(
814 const comp = elf_file.base.comp;829 const comp = elf_file.base.comp;
815 const gpa = comp.gpa;830 const gpa = comp.gpa;
816 const cpu_arch = elf_file.getTarget().cpu.arch;831 const cpu_arch = elf_file.getTarget().cpu.arch;
817 const P = self.address(elf_file) + rel.r_offset;832 const P: u64 = @intCast(self.address(elf_file) + @as(i64, @intCast(rel.r_offset)));
818 const A = rel.r_addend;833 const A = rel.r_addend;
819 const S = @as(i64, @intCast(target.address(.{}, elf_file)));834 const S = target.address(.{}, elf_file);
820 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;835 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
821836
822 const num_dynrelocs = switch (self.file(elf_file).?) {837 const num_dynrelocs = switch (self.file(elf_file).?) {
...@@ -884,7 +899,7 @@ fn resolveDynAbsReloc(...@@ -884,7 +899,7 @@ fn resolveDynAbsReloc(
884 },899 },
885900
886 .ifunc => {901 .ifunc => {
887 const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file)));902 const S_ = target.address(.{ .plt = false }, elf_file);
888 elf_file.addRelaDynAssumeCapacity(.{903 elf_file.addRelaDynAssumeCapacity(.{
889 .offset = P,904 .offset = P,
890 .type = relocation.encode(.irel, cpu_arch),905 .type = relocation.encode(.irel, cpu_arch),
...@@ -924,6 +939,11 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -924,6 +939,11 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
924 else => unreachable,939 else => unreachable,
925 };940 };
926 const target = elf_file.symbol(target_index);941 const target = elf_file.symbol(target_index);
942 const is_synthetic_symbol = switch (file_ptr) {
943 .zig_object => false, // TODO: implement this once we support merge sections in ZigObject
944 .object => |x| rel.r_sym() >= x.symtab.items.len,
945 else => unreachable,
946 };
927947
928 // Check for violation of One Definition Rule for COMDATs.948 // Check for violation of One Definition Rule for COMDATs.
929 if (target.file(elf_file) == null) {949 if (target.file(elf_file) == null) {
...@@ -937,20 +957,21 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -937,20 +957,21 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
937 }957 }
938958
939 // Report an undefined symbol.959 // Report an undefined symbol.
940 if (try self.reportUndefined(elf_file, target, target_index, rel, undefs)) continue;960 if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs)))
961 continue;
941962
942 // We will use equation format to resolve relocations:963 // We will use equation format to resolve relocations:
943 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/964 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
944 //965 //
945 const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));966 const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));
946 // Addend from the relocation.967 // Addend from the relocation.
947 const A = rel.r_addend;968 const A = rel.r_addend;
948 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.969 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
949 const S = @as(i64, @intCast(target.address(.{}, elf_file)));970 const S = target.address(.{}, elf_file);
950 // Address of the global offset table.971 // Address of the global offset table.
951 const GOT = @as(i64, @intCast(elf_file.gotAddress()));972 const GOT = elf_file.gotAddress();
952 // Address of the dynamic thread pointer.973 // Address of the dynamic thread pointer.
953 const DTP = @as(i64, @intCast(elf_file.dtpAddress()));974 const DTP = elf_file.dtpAddress();
954975
955 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 };976 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 };
956977
...@@ -984,6 +1005,35 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -984,6 +1005,35 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
984 if (has_reloc_errors) return error.RelocFailure;1005 if (has_reloc_errors) return error.RelocFailure;
985}1006}
9861007
1008const 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
1016pub 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
1029pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {
1030 return elf_file.atomExtra(atom.extra_index);
1031}
1032
1033pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
1034 elf_file.setAtomExtra(atom.extra_index, extras);
1035}
1036
987pub fn format(1037pub fn format(
988 atom: Atom,1038 atom: Atom,
989 comptime unused_fmt_string: []const u8,1039 comptime unused_fmt_string: []const u8,
...@@ -1023,12 +1073,13 @@ fn format2(...@@ -1023,12 +1073,13 @@ fn format2(
1023 atom.atom_index, atom.name(elf_file), atom.address(elf_file),1073 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
1024 atom.output_section_index, atom.alignment, atom.size,1074 atom.output_section_index, atom.alignment, atom.size,
1025 });1075 });
1026 if (atom.fde_start != atom.fde_end) {1076 if (atom.flags.fde) {
1027 try writer.writeAll(" : fdes{ ");1077 try writer.writeAll(" : fdes{ ");
1028 for (atom.fdes(elf_file), atom.fde_start..) |fde, i| {1078 const extras = atom.extra(elf_file).?;
1079 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
1029 try writer.print("{d}", .{i});1080 try writer.print("{d}", .{i});
1030 if (!fde.alive) try writer.writeAll("([*])");1081 if (!fde.alive) try writer.writeAll("([*])");
1031 if (i < atom.fde_end - 1) try writer.writeAll(", ");1082 if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
1032 }1083 }
1033 try writer.writeAll(" }");1084 try writer.writeAll(" }");
1034 }1085 }
...@@ -1045,6 +1096,12 @@ pub const Flags = packed struct {...@@ -1045,6 +1096,12 @@ pub const Flags = packed struct {
10451096
1046 /// Specifies if the atom has been visited during garbage collection.1097 /// Specifies if the atom has been visited during garbage collection.
1047 visited: bool = false,1098 visited: bool = false,
1099
1100 /// Whether this atom has a range extension thunk.
1101 thunk: bool = false,
1102
1103 /// Whether this atom has FDE records.
1104 fde: bool = false,
1048};1105};
10491106
1050const x86_64 = struct {1107const x86_64 = struct {
...@@ -1235,10 +1292,10 @@ const x86_64 = struct {...@@ -1235,10 +1292,10 @@ const x86_64 = struct {
12351292
1236 .TLSGD => {1293 .TLSGD => {
1237 if (target.flags.has_tlsgd) {1294 if (target.flags.has_tlsgd) {
1238 const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));1295 const S_ = target.tlsGdAddress(elf_file);
1239 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1296 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1240 } else if (target.flags.has_gottp) {1297 } else if (target.flags.has_gottp) {
1241 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));1298 const S_ = target.gotTpAddress(elf_file);
1242 try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);1299 try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);
1243 } else {1300 } else {
1244 try x86_64.relaxTlsGdToLe(1301 try x86_64.relaxTlsGdToLe(
...@@ -1254,13 +1311,13 @@ const x86_64 = struct {...@@ -1254,13 +1311,13 @@ const x86_64 = struct {
1254 .TLSLD => {1311 .TLSLD => {
1255 if (elf_file.got.tlsld_index) |entry_index| {1312 if (elf_file.got.tlsld_index) |entry_index| {
1256 const tlsld_entry = elf_file.got.entries.items[entry_index];1313 const tlsld_entry = elf_file.got.entries.items[entry_index];
1257 const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));1314 const S_ = tlsld_entry.address(elf_file);
1258 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1315 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1259 } else {1316 } else {
1260 try x86_64.relaxTlsLdToLe(1317 try x86_64.relaxTlsLdToLe(
1261 atom,1318 atom,
1262 &.{ rel, it.next().? },1319 &.{ rel, it.next().? },
1263 @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))),1320 @as(i32, @intCast(TP - elf_file.tlsAddress())),
1264 elf_file,1321 elf_file,
1265 stream,1322 stream,
1266 );1323 );
...@@ -1269,7 +1326,7 @@ const x86_64 = struct {...@@ -1269,7 +1326,7 @@ const x86_64 = struct {
12691326
1270 .GOTPC32_TLSDESC => {1327 .GOTPC32_TLSDESC => {
1271 if (target.flags.has_tlsdesc) {1328 if (target.flags.has_tlsdesc) {
1272 const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));1329 const S_ = target.tlsDescAddress(elf_file);
1273 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1330 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1274 } else {1331 } else {
1275 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {1332 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
...@@ -1293,7 +1350,7 @@ const x86_64 = struct {...@@ -1293,7 +1350,7 @@ const x86_64 = struct {
12931350
1294 .GOTTPOFF => {1351 .GOTTPOFF => {
1295 if (target.flags.has_gottp) {1352 if (target.flags.has_gottp) {
1296 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));1353 const S_ = target.gotTpAddress(elf_file);
1297 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1354 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1298 } else {1355 } else {
1299 x86_64.relaxGotTpOff(code[r_offset - 3 ..]);1356 x86_64.relaxGotTpOff(code[r_offset - 3 ..]);
...@@ -1336,9 +1393,18 @@ const x86_64 = struct {...@@ -1336,9 +1393,18 @@ const x86_64 = struct {
1336 .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),1393 .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
1337 .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),1394 .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
1338 .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),1395 .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
1339 .@"64" => try cwriter.writeInt(i64, S + A, .little),1396 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1340 .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),1397 try cwriter.writeInt(u64, value, .little)
1341 .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),1398 else
1399 try cwriter.writeInt(i64, S + A, .little),
1400 .DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1401 try cwriter.writeInt(u64, value, .little)
1402 else
1403 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
1404 .DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1405 try cwriter.writeInt(u64, value, .little)
1406 else
1407 try cwriter.writeInt(i64, S + A - DTP, .little),
1342 .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),1408 .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),
1343 .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),1409 .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
1344 .SIZE32 => {1410 .SIZE32 => {
...@@ -1720,7 +1786,7 @@ const aarch64 = struct {...@@ -1720,7 +1786,7 @@ const aarch64 = struct {
1720 .object => |x| x.symbols.items[rel.r_sym()],1786 .object => |x| x.symbols.items[rel.r_sym()],
1721 else => unreachable,1787 else => unreachable,
1722 };1788 };
1723 const S_: i64 = @intCast(th.targetAddress(target_index, elf_file));1789 const S_ = th.targetAddress(target_index, elf_file);
1724 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;1790 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
1725 };1791 };
1726 aarch64_util.writeBranchImm(disp, code);1792 aarch64_util.writeBranchImm(disp, code);
...@@ -1738,16 +1804,12 @@ const aarch64 = struct {...@@ -1738,16 +1804,12 @@ const aarch64 = struct {
17381804
1739 .ADR_PREL_PG_HI21 => {1805 .ADR_PREL_PG_HI21 => {
1740 // TODO: check for relaxation of ADRP+ADD1806 // TODO: check for relaxation of ADRP+ADD
1741 const saddr = @as(u64, @intCast(P));1807 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A)));
1742 const taddr = @as(u64, @intCast(S + A));
1743 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)));
1744 aarch64_util.writeAdrpInst(pages, code);1808 aarch64_util.writeAdrpInst(pages, code);
1745 },1809 },
17461810
1747 .ADR_GOT_PAGE => if (target.flags.has_got) {1811 .ADR_GOT_PAGE => if (target.flags.has_got) {
1748 const saddr = @as(u64, @intCast(P));1812 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A)));
1749 const taddr = @as(u64, @intCast(G + GOT + A));
1750 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)));
1751 aarch64_util.writeAdrpInst(pages, code);1813 aarch64_util.writeAdrpInst(pages, code);
1752 } else {1814 } else {
1753 // TODO: relax1815 // TODO: relax
...@@ -1802,46 +1864,38 @@ const aarch64 = struct {...@@ -1802,46 +1864,38 @@ const aarch64 = struct {
1802 },1864 },
18031865
1804 .TLSIE_ADR_GOTTPREL_PAGE21 => {1866 .TLSIE_ADR_GOTTPREL_PAGE21 => {
1805 const S_: i64 = @intCast(target.gotTpAddress(elf_file));1867 const S_ = target.gotTpAddress(elf_file);
1806 const saddr: u64 = @intCast(P);1868 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1807 const taddr: u64 = @intCast(S_ + A);1869 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1808 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });
1809 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr));
1810 aarch64_util.writeAdrpInst(pages, code);1870 aarch64_util.writeAdrpInst(pages, code);
1811 },1871 },
18121872
1813 .TLSIE_LD64_GOTTPREL_LO12_NC => {1873 .TLSIE_LD64_GOTTPREL_LO12_NC => {
1814 const S_: i64 = @intCast(target.gotTpAddress(elf_file));1874 const S_ = target.gotTpAddress(elf_file);
1815 const taddr: u64 = @intCast(S_ + A);1875 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1816 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });1876 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1817 const offset: u12 = try math.divExact(u12, @truncate(taddr), 8);
1818 aarch64_util.writeLoadStoreRegInst(offset, code);1877 aarch64_util.writeLoadStoreRegInst(offset, code);
1819 },1878 },
18201879
1821 .TLSGD_ADR_PAGE21 => {1880 .TLSGD_ADR_PAGE21 => {
1822 const S_: i64 = @intCast(target.tlsGdAddress(elf_file));1881 const S_ = target.tlsGdAddress(elf_file);
1823 const saddr: u64 = @intCast(P);1882 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1824 const taddr: u64 = @intCast(S_ + A);1883 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1825 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });
1826 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr));
1827 aarch64_util.writeAdrpInst(pages, code);1884 aarch64_util.writeAdrpInst(pages, code);
1828 },1885 },
18291886
1830 .TLSGD_ADD_LO12_NC => {1887 .TLSGD_ADD_LO12_NC => {
1831 const S_: i64 = @intCast(target.tlsGdAddress(elf_file));1888 const S_ = target.tlsGdAddress(elf_file);
1832 const taddr: u64 = @intCast(S_ + A);1889 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1833 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });1890 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1834 const offset: u12 = @truncate(taddr);
1835 aarch64_util.writeAddImmInst(offset, code);1891 aarch64_util.writeAddImmInst(offset, code);
1836 },1892 },
18371893
1838 .TLSDESC_ADR_PAGE21 => {1894 .TLSDESC_ADR_PAGE21 => {
1839 if (target.flags.has_tlsdesc) {1895 if (target.flags.has_tlsdesc) {
1840 const S_: i64 = @intCast(target.tlsDescAddress(elf_file));1896 const S_ = target.tlsDescAddress(elf_file);
1841 const saddr: u64 = @intCast(P);1897 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1842 const taddr: u64 = @intCast(S_ + A);1898 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1843 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });
1844 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr));
1845 aarch64_util.writeAdrpInst(pages, code);1899 aarch64_util.writeAdrpInst(pages, code);
1846 } else {1900 } else {
1847 relocs_log.debug(" relaxing adrp => nop", .{});1901 relocs_log.debug(" relaxing adrp => nop", .{});
...@@ -1851,10 +1905,9 @@ const aarch64 = struct {...@@ -1851,10 +1905,9 @@ const aarch64 = struct {
18511905
1852 .TLSDESC_LD64_LO12 => {1906 .TLSDESC_LD64_LO12 => {
1853 if (target.flags.has_tlsdesc) {1907 if (target.flags.has_tlsdesc) {
1854 const S_: i64 = @intCast(target.tlsDescAddress(elf_file));1908 const S_ = target.tlsDescAddress(elf_file);
1855 const taddr: u64 = @intCast(S_ + A);1909 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1856 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });1910 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1857 const offset: u12 = try math.divExact(u12, @truncate(taddr), 8);
1858 aarch64_util.writeLoadStoreRegInst(offset, code);1911 aarch64_util.writeLoadStoreRegInst(offset, code);
1859 } else {1912 } else {
1860 relocs_log.debug(" relaxing ldr => nop", .{});1913 relocs_log.debug(" relaxing ldr => nop", .{});
...@@ -1864,10 +1917,9 @@ const aarch64 = struct {...@@ -1864,10 +1917,9 @@ const aarch64 = struct {
18641917
1865 .TLSDESC_ADD_LO12 => {1918 .TLSDESC_ADD_LO12 => {
1866 if (target.flags.has_tlsdesc) {1919 if (target.flags.has_tlsdesc) {
1867 const S_: i64 = @intCast(target.tlsDescAddress(elf_file));1920 const S_ = target.tlsDescAddress(elf_file);
1868 const taddr: u64 = @intCast(S_ + A);1921 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1869 relocs_log.debug(" [{x} => {x}]", .{ P, taddr });1922 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1870 const offset: u12 = @truncate(taddr);
1871 aarch64_util.writeAddImmInst(offset, code);1923 aarch64_util.writeAddImmInst(offset, code);
1872 } else {1924 } else {
1873 const old_inst = Instruction{1925 const old_inst = Instruction{
...@@ -1912,7 +1964,6 @@ const aarch64 = struct {...@@ -1912,7 +1964,6 @@ const aarch64 = struct {
1912 ) !void {1964 ) !void {
1913 _ = it;1965 _ = it;
1914 _ = code;1966 _ = code;
1915 _ = target;
19161967
1917 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1968 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1918 const cwriter = stream.writer();1969 const cwriter = stream.writer();
...@@ -1922,7 +1973,10 @@ const aarch64 = struct {...@@ -1922,7 +1973,10 @@ const aarch64 = struct {
1922 switch (r_type) {1973 switch (r_type) {
1923 .NONE => unreachable,1974 .NONE => unreachable,
1924 .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),1975 .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
1925 .ABS64 => try cwriter.writeInt(i64, S + A, .little),1976 .ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1977 try cwriter.writeInt(u64, value, .little)
1978 else
1979 try cwriter.writeInt(i64, S + A, .little),
1926 else => try atom.reportUnhandledRelocError(rel, elf_file),1980 else => try atom.reportUnhandledRelocError(rel, elf_file),
1927 }1981 }
1928 }1982 }
...@@ -2047,7 +2101,7 @@ const riscv = struct {...@@ -2047,7 +2101,7 @@ const riscv = struct {
2047 const atom_addr = atom.address(elf_file);2101 const atom_addr = atom.address(elf_file);
2048 const pos = it.pos;2102 const pos = it.pos;
2049 const pair = while (it.prev()) |pair| {2103 const pair = while (it.prev()) |pair| {
2050 if (S == atom_addr + pair.r_offset) break pair;2104 if (S == atom_addr + @as(i64, @intCast(pair.r_offset))) break pair;
2051 } else {2105 } else {
2052 // TODO: implement searching forward2106 // TODO: implement searching forward
2053 var err = try elf_file.addErrorWithNotes(1);2107 var err = try elf_file.addErrorWithNotes(1);
...@@ -2065,10 +2119,10 @@ const riscv = struct {...@@ -2065,10 +2119,10 @@ const riscv = struct {
2065 .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]),2119 .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]),
2066 else => unreachable,2120 else => unreachable,
2067 };2121 };
2068 const S_ = @as(i64, @intCast(target_.address(.{}, elf_file)));2122 const S_ = target_.address(.{}, elf_file);
2069 const A_ = pair.r_addend;2123 const A_ = pair.r_addend;
2070 const P_ = @as(i64, @intCast(atom_addr + pair.r_offset));2124 const P_ = atom_addr + @as(i64, @intCast(pair.r_offset));
2071 const G_ = @as(i64, @intCast(target_.gotAddress(elf_file))) - GOT;2125 const G_ = target_.gotAddress(elf_file) - GOT;
2072 const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) {2126 const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) {
2073 .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow,2127 .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow,
2074 .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow,2128 .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow,
...@@ -2096,7 +2150,6 @@ const riscv = struct {...@@ -2096,7 +2150,6 @@ const riscv = struct {
2096 code: []u8,2150 code: []u8,
2097 stream: anytype,2151 stream: anytype,
2098 ) !void {2152 ) !void {
2099 _ = target;
2100 _ = it;2153 _ = it;
21012154
2102 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());2155 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
...@@ -2111,7 +2164,10 @@ const riscv = struct {...@@ -2111,7 +2164,10 @@ const riscv = struct {
2111 .NONE => unreachable,2164 .NONE => unreachable,
21122165
2113 .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),2166 .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
2114 .@"64" => try cwriter.writeInt(i64, S + A, .little),2167 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
2168 try cwriter.writeInt(u64, value, .little)
2169 else
2170 try cwriter.writeInt(i64, S + A, .little),
21152171
2116 .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A),2172 .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A),
2117 .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A),2173 .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A),
...@@ -2170,6 +2226,23 @@ const RelocsIterator = struct {...@@ -2170,6 +2226,23 @@ const RelocsIterator = struct {
2170 }2226 }
2171};2227};
21722228
2229pub 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
2173const std = @import("std");2246const std = @import("std");
2174const assert = std.debug.assert;2247const assert = std.debug.assert;
2175const elf = std.elf;2248const elf = std.elf;
src/link/Elf/LinkerDefined.zig+2-2
...@@ -60,10 +60,10 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void {...@@ -60,10 +60,10 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void {
60 if (file_ptr.index() != self.index) continue;60 if (file_ptr.index() != self.index) continue;
61 global.flags.output_symtab = true;61 global.flags.output_symtab = true;
62 if (global.isLocal(elf_file)) {62 if (global.isLocal(elf_file)) {
63 try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file);63 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
64 self.output_symtab_ctx.nlocals += 1;64 self.output_symtab_ctx.nlocals += 1;
65 } else {65 } else {
66 try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file);66 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
67 self.output_symtab_ctx.nglobals += 1;67 self.output_symtab_ctx.nglobals += 1;
68 }68 }
69 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;69 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
src/link/Elf/Object.zig+230-19
...@@ -15,6 +15,8 @@ comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},...@@ -15,6 +15,8 @@ comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
15comdat_group_data: std.ArrayListUnmanaged(u32) = .{},15comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
16relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},16relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
1717
18merge_sections: std.ArrayListUnmanaged(InputMergeSection.Index) = .{},
19
18fdes: std.ArrayListUnmanaged(Fde) = .{},20fdes: std.ArrayListUnmanaged(Fde) = .{},
19cies: std.ArrayListUnmanaged(Cie) = .{},21cies: std.ArrayListUnmanaged(Cie) = .{},
20eh_frame_data: std.ArrayListUnmanaged(u8) = .{},22eh_frame_data: std.ArrayListUnmanaged(u8) = .{},
...@@ -51,6 +53,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -51,6 +53,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
51 self.fdes.deinit(allocator);53 self.fdes.deinit(allocator);
52 self.cies.deinit(allocator);54 self.cies.deinit(allocator);
53 self.eh_frame_data.deinit(allocator);55 self.eh_frame_data.deinit(allocator);
56 self.merge_sections.deinit(allocator);
54}57}
5558
56pub fn parse(self: *Object, elf_file: *Elf) !void {59pub fn parse(self: *Object, elf_file: *Elf) !void {
...@@ -242,11 +245,12 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:...@@ -242,11 +245,12 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
242 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));245 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
243 defer allocator.free(relocs);246 defer allocator.free(relocs);
244 atom.relocs_section_index = @intCast(i);247 atom.relocs_section_index = @intCast(i);
245 atom.rel_index = @intCast(self.relocs.items.len);248 const rel_index: u32 = @intCast(self.relocs.items.len);
246 atom.rel_num = @intCast(relocs.len);249 const rel_count: u32 = @intCast(relocs.len);
250 try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
247 try self.relocs.appendUnalignedSlice(allocator, relocs);251 try self.relocs.appendUnalignedSlice(allocator, relocs);
248 if (elf_file.getTarget().cpu.arch == .riscv64) {252 if (elf_file.getTarget().cpu.arch == .riscv64) {
249 sortRelocs(self.relocs.items[atom.rel_index..][0..atom.rel_num]);253 sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
250 }254 }
251 }255 }
252 },256 },
...@@ -279,8 +283,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O...@@ -279,8 +283,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O
279 const name = blk: {283 const name = blk: {
280 const name = self.getString(shdr.sh_name);284 const name = self.getString(shdr.sh_name);
281 if (elf_file.base.isRelocatable()) break :blk name;285 if (elf_file.base.isRelocatable()) break :blk name;
282 if (shdr.sh_flags & elf.SHF_MERGE != 0 and shdr.sh_flags & elf.SHF_STRINGS == 0)286 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
283 break :blk name; // TODO: consider dropping SHF_STRINGS once ICF is implemented
284 const sh_name_prefixes: []const [:0]const u8 = &.{287 const sh_name_prefixes: []const [:0]const u8 = &.{
285 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",288 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
286 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",289 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",
...@@ -334,7 +337,6 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {...@@ -334,7 +337,6 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
334 const name = self.getString(shdr.sh_name);337 const name = self.getString(shdr.sh_name);
335 const ignore = blk: {338 const ignore = blk: {
336 if (mem.startsWith(u8, name, ".note")) break :blk true;339 if (mem.startsWith(u8, name, ".note")) break :blk true;
337 if (mem.startsWith(u8, name, ".comment")) break :blk true;
338 if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true;340 if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true;
339 if (mem.startsWith(u8, name, ".riscv.attributes")) break :blk true; // TODO: riscv attributes341 if (mem.startsWith(u8, name, ".riscv.attributes")) break :blk true; // TODO: riscv attributes
340 if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and342 if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and
...@@ -353,7 +355,7 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {...@@ -353,7 +355,7 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
353 const index = try elf_file.addSymbol();355 const index = try elf_file.addSymbol();
354 self.symbols.appendAssumeCapacity(index);356 self.symbols.appendAssumeCapacity(index);
355 const sym_ptr = elf_file.symbol(index);357 const sym_ptr = elf_file.symbol(index);
356 sym_ptr.value = sym.st_value;358 sym_ptr.value = @intCast(sym.st_value);
357 sym_ptr.name_offset = sym.st_name;359 sym_ptr.name_offset = sym.st_name;
358 sym_ptr.esym_index = @as(u32, @intCast(i));360 sym_ptr.esym_index = @as(u32, @intCast(i));
359 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];361 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
...@@ -445,13 +447,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:...@@ -445,13 +447,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
445 while (i < self.fdes.items.len) {447 while (i < self.fdes.items.len) {
446 const fde = self.fdes.items[i];448 const fde = self.fdes.items[i];
447 const atom = fde.atom(elf_file);449 const atom = fde.atom(elf_file);
448 atom.fde_start = i;450 const start = i;
449 i += 1;451 i += 1;
450 while (i < self.fdes.items.len) : (i += 1) {452 while (i < self.fdes.items.len) : (i += 1) {
451 const next_fde = self.fdes.items[i];453 const next_fde = self.fdes.items[i];
452 if (atom.atom_index != next_fde.atom(elf_file).atom_index) break;454 if (atom.atom_index != next_fde.atom(elf_file).atom_index) break;
453 }455 }
454 atom.fde_end = i;456 try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
457 atom.flags.fde = true;
455 }458 }
456}459}
457460
...@@ -545,7 +548,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -545,7 +548,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
545 elf.SHN_ABS, elf.SHN_COMMON => 0,548 elf.SHN_ABS, elf.SHN_COMMON => 0,
546 else => self.atoms.items[esym.st_shndx],549 else => self.atoms.items[esym.st_shndx],
547 };550 };
548 global.value = esym.st_value;551 global.value = @intCast(esym.st_value);
549 global.atom_index = atom_index;552 global.atom_index = atom_index;
550 global.esym_index = esym_index;553 global.esym_index = esym_index;
551 global.file_index = self.index;554 global.file_index = self.index;
...@@ -657,6 +660,178 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO...@@ -657,6 +660,178 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
657 }660 }
658}661}
659662
663pub 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
740pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
741 const gpa = elf_file.base.comp.gpa;
742
743 for (self.merge_sections.items) |index| {
744 const imsec = elf_file.inputMergeSection(index) orelse continue;
745 if (imsec.offsets.items.len == 0) continue;
746 const msec = elf_file.mergeSection(imsec.merge_section_index);
747 const atom_ptr = elf_file.atom(imsec.atom_index).?;
748 const isec = atom_ptr.inputShdr(elf_file);
749
750 try imsec.subsections.resize(gpa, imsec.strings.items.len);
751
752 for (imsec.strings.items, imsec.subsections.items) |str, *imsec_msub| {
753 const string = imsec.bytes.items[str.pos..][0..str.len];
754 const res = try msec.insert(gpa, string);
755 if (!res.found_existing) {
756 const msub_index = try elf_file.addMergeSubsection();
757 const msub = elf_file.mergeSubsection(msub_index);
758 msub.merge_section_index = imsec.merge_section_index;
759 msub.string_index = res.key.pos;
760 msub.alignment = atom_ptr.alignment;
761 msub.size = res.key.len;
762 msub.entsize = math.cast(u32, isec.sh_entsize) orelse return error.Overflow;
763 msub.alive = !elf_file.base.gc_sections or isec.sh_flags & elf.SHF_ALLOC == 0;
764 res.sub.* = msub_index;
765 }
766 imsec_msub.* = res.sub.*;
767 }
768
769 imsec.clearAndFree(gpa);
770 }
771
772 for (self.symtab.items, 0..) |*esym, idx| {
773 const sym_index = self.symbols.items[idx];
774 const sym = elf_file.symbol(sym_index);
775
776 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
777
778 const imsec_index = self.merge_sections.items[esym.st_shndx];
779 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
780 if (imsec.offsets.items.len == 0) continue;
781 const msub_index, const offset = imsec.findSubsection(@intCast(esym.st_value)) orelse {
782 var err = try elf_file.addErrorWithNotes(2);
783 try err.addMsg(elf_file, "invalid symbol value: {x}", .{esym.st_value});
784 try err.addNote(elf_file, "for symbol {s}", .{sym.name(elf_file)});
785 try err.addNote(elf_file, "in {}", .{self.fmtPath()});
786 return error.MalformedObject;
787 };
788
789 try sym.addExtra(.{ .subsection = msub_index }, elf_file);
790 sym.flags.merge_subsection = true;
791 sym.value = offset;
792 }
793
794 for (self.atoms.items) |atom_index| {
795 const atom_ptr = elf_file.atom(atom_index) orelse continue;
796 if (!atom_ptr.flags.alive) continue;
797 const extras = atom_ptr.extra(elf_file) orelse continue;
798 const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];
799 for (relocs) |*rel| {
800 const esym = self.symtab.items[rel.r_sym()];
801 if (esym.st_type() != elf.STT_SECTION) continue;
802
803 const imsec_index = self.merge_sections.items[esym.st_shndx];
804 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
805 if (imsec.offsets.items.len == 0) continue;
806 const msub_index, const offset = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
807 var err = try elf_file.addErrorWithNotes(1);
808 try err.addMsg(elf_file, "invalid relocation at offset 0x{x}", .{rel.r_offset});
809 try err.addNote(elf_file, "in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
810 return error.MalformedObject;
811 };
812 const msub = elf_file.mergeSubsection(msub_index);
813 const msec = msub.mergeSection(elf_file);
814
815 const out_sym_idx: u64 = @intCast(self.symbols.items.len);
816 try self.symbols.ensureUnusedCapacity(gpa, 1);
817 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), msub_index });
818 defer gpa.free(name);
819 const sym_index = try elf_file.addSymbol();
820 const sym = elf_file.symbol(sym_index);
821 sym.* = .{
822 .value = @bitCast(@as(i64, @intCast(offset)) - rel.r_addend),
823 .name_offset = try self.addString(gpa, name),
824 .esym_index = rel.r_sym(),
825 .file_index = self.index,
826 };
827 try sym.addExtra(.{ .subsection = msub_index }, elf_file);
828 sym.flags.merge_subsection = true;
829 self.symbols.addOneAssumeCapacity().* = sym_index;
830 rel.r_info = (out_sym_idx << 32) | rel.r_type();
831 }
832 }
833}
834
660/// We will create dummy shdrs per each resolved common symbols to make it835/// We will create dummy shdrs per each resolved common symbols to make it
661/// play nicely with the rest of the system.836/// play nicely with the rest of the system.
662pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {837pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
...@@ -747,6 +922,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {...@@ -747,6 +922,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
747922
748 for (self.locals()) |local_index| {923 for (self.locals()) |local_index| {
749 const local = elf_file.symbol(local_index);924 const local = elf_file.symbol(local_index);
925 if (local.mergeSubsection(elf_file)) |msub| {
926 if (!msub.alive) continue;
927 local.output_section_index = msub.mergeSection(elf_file).output_section_index;
928 continue;
929 }
750 const atom = local.atom(elf_file) orelse continue;930 const atom = local.atom(elf_file) orelse continue;
751 if (!atom.flags.alive) continue;931 if (!atom.flags.alive) continue;
752 local.output_section_index = atom.output_section_index;932 local.output_section_index = atom.output_section_index;
...@@ -754,11 +934,23 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {...@@ -754,11 +934,23 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
754934
755 for (self.globals()) |global_index| {935 for (self.globals()) |global_index| {
756 const global = elf_file.symbol(global_index);936 const global = elf_file.symbol(global_index);
937 if (global.file(elf_file).?.index() != self.index) continue;
938 if (global.mergeSubsection(elf_file)) |msub| {
939 if (!msub.alive) continue;
940 global.output_section_index = msub.mergeSection(elf_file).output_section_index;
941 continue;
942 }
757 const atom = global.atom(elf_file) orelse continue;943 const atom = global.atom(elf_file) orelse continue;
758 if (!atom.flags.alive) continue;944 if (!atom.flags.alive) continue;
759 if (global.file(elf_file).?.index() != self.index) continue;
760 global.output_section_index = atom.output_section_index;945 global.output_section_index = atom.output_section_index;
761 }946 }
947
948 for (self.symbols.items[self.symtab.items.len..]) |local_index| {
949 const local = elf_file.symbol(local_index);
950 const msub = local.mergeSubsection(elf_file).?;
951 if (!msub.alive) continue;
952 local.output_section_index = msub.mergeSection(elf_file).output_section_index;
953 }
762}954}
763955
764pub fn initRelaSections(self: Object, elf_file: *Elf) !void {956pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
...@@ -843,9 +1035,17 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {...@@ -843,9 +1035,17 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
843}1035}
8441036
845pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {1037pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1038 const isAlive = struct {
1039 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
1040 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
1041 if (sym.atom(ctx)) |atom_ptr| return atom_ptr.flags.alive;
1042 return true;
1043 }
1044 }.isAlive;
1045
846 for (self.locals()) |local_index| {1046 for (self.locals()) |local_index| {
847 const local = elf_file.symbol(local_index);1047 const local = elf_file.symbol(local_index);
848 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;1048 if (!isAlive(local, elf_file)) continue;
849 const esym = local.elfSym(elf_file);1049 const esym = local.elfSym(elf_file);
850 switch (esym.st_type()) {1050 switch (esym.st_type()) {
851 elf.STT_SECTION => continue,1051 elf.STT_SECTION => continue,
...@@ -853,7 +1053,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -853,7 +1053,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
853 else => {},1053 else => {},
854 }1054 }
855 local.flags.output_symtab = true;1055 local.flags.output_symtab = true;
856 try local.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file);1056 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
857 self.output_symtab_ctx.nlocals += 1;1057 self.output_symtab_ctx.nlocals += 1;
858 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;1058 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
859 }1059 }
...@@ -862,13 +1062,13 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -862,13 +1062,13 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
862 const global = elf_file.symbol(global_index);1062 const global = elf_file.symbol(global_index);
863 const file_ptr = global.file(elf_file) orelse continue;1063 const file_ptr = global.file(elf_file) orelse continue;
864 if (file_ptr.index() != self.index) continue;1064 if (file_ptr.index() != self.index) continue;
865 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;1065 if (!isAlive(global, elf_file)) continue;
866 global.flags.output_symtab = true;1066 global.flags.output_symtab = true;
867 if (global.isLocal(elf_file)) {1067 if (global.isLocal(elf_file)) {
868 try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file);1068 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
869 self.output_symtab_ctx.nlocals += 1;1069 self.output_symtab_ctx.nlocals += 1;
870 } else {1070 } else {
871 try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file);1071 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
872 self.output_symtab_ctx.nglobals += 1;1072 self.output_symtab_ctx.nglobals += 1;
873 }1073 }
874 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;1074 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
...@@ -902,14 +1102,16 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {...@@ -902,14 +1102,16 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
9021102
903pub fn locals(self: Object) []const Symbol.Index {1103pub fn locals(self: Object) []const Symbol.Index {
904 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};1104 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
905 const end = self.first_global orelse self.symbols.items.len;1105 assert(self.symbols.items.len >= self.symtab.items.len);
1106 const end = self.first_global orelse self.symtab.items.len;
906 return self.symbols.items[0..end];1107 return self.symbols.items[0..end];
907}1108}
9081109
909pub fn globals(self: Object) []const Symbol.Index {1110pub fn globals(self: Object) []const Symbol.Index {
910 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};1111 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
911 const start = self.first_global orelse self.symbols.items.len;1112 assert(self.symbols.items.len >= self.symtab.items.len);
912 return self.symbols.items[start..];1113 const start = self.first_global orelse self.symtab.items.len;
1114 return self.symbols.items[start..self.symtab.items.len];
913}1115}
9141116
915/// Returns atom's code and optionally uncompresses data if required (for compressed sections).1117/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
...@@ -954,6 +1156,14 @@ pub fn getString(self: Object, off: u32) [:0]const u8 {...@@ -954,6 +1156,14 @@ pub fn getString(self: Object, off: u32) [:0]const u8 {
954 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);1156 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
955}1157}
9561158
1159fn addString(self: *Object, allocator: Allocator, str: []const u8) !u32 {
1160 const off: u32 = @intCast(self.strtab.items.len);
1161 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
1162 self.strtab.appendSliceAssumeCapacity(str);
1163 self.strtab.appendAssumeCapacity(0);
1164 return off;
1165}
1166
957/// Caller owns the memory.1167/// Caller owns the memory.
958fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 {1168fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 {
959 assert(index < self.shdrs.items.len);1169 assert(index < self.shdrs.items.len);
...@@ -1159,5 +1369,6 @@ const Cie = eh_frame.Cie;...@@ -1159,5 +1369,6 @@ const Cie = eh_frame.Cie;
1159const Elf = @import("../Elf.zig");1369const Elf = @import("../Elf.zig");
1160const Fde = eh_frame.Fde;1370const Fde = eh_frame.Fde;
1161const File = @import("file.zig").File;1371const File = @import("file.zig").File;
1372const InputMergeSection = @import("merge_section.zig").InputMergeSection;
1162const Symbol = @import("Symbol.zig");1373const Symbol = @import("Symbol.zig");
1163const Alignment = Atom.Alignment;1374const Alignment = Atom.Alignment;
src/link/Elf/SharedObject.zig+2-2
...@@ -231,7 +231,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {...@@ -231,7 +231,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
231231
232 const global = elf_file.symbol(index);232 const global = elf_file.symbol(index);
233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
234 global.value = this_sym.st_value;234 global.value = @intCast(this_sym.st_value);
235 global.atom_index = 0;235 global.atom_index = 0;
236 global.esym_index = esym_index;236 global.esym_index = esym_index;
237 global.version_index = self.versyms.items[esym_index];237 global.version_index = self.versyms.items[esym_index];
...@@ -269,7 +269,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void {...@@ -269,7 +269,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void {
269 if (file_ptr.index() != self.index) continue;269 if (file_ptr.index() != self.index) continue;
270 if (global.isLocal(elf_file)) continue;270 if (global.isLocal(elf_file)) continue;
271 global.flags.output_symtab = true;271 global.flags.output_symtab = true;
272 try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file);272 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
273 self.output_symtab_ctx.nglobals += 1;273 self.output_symtab_ctx.nglobals += 1;
274 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;274 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
275 }275 }
src/link/Elf/Symbol.zig+67-31
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1//! Represents a defined symbol.1//! Represents a defined symbol.
22
3/// Allocated address value of this symbol.3/// Allocated address value of this symbol.
4value: u64 = 0,4value: i64 = 0,
55
6/// Offset into the linker's string table.6/// Offset into the linker's string table.
7name_offset: u32 = 0,7name_offset: u32 = 0,
...@@ -14,7 +14,7 @@ file_index: File.Index = 0,...@@ -14,7 +14,7 @@ file_index: File.Index = 0,
14/// Use `atom` to get the pointer to the atom.14/// Use `atom` to get the pointer to the atom.
15atom_index: Atom.Index = 0,15atom_index: Atom.Index = 0,
1616
17/// Assigned output section index for this atom.17/// Assigned output section index for this symbol.
18output_section_index: u32 = 0,18output_section_index: u32 = 0,
1919
20/// Index of the source symbol this symbol references.20/// Index of the source symbol this symbol references.
...@@ -33,7 +33,8 @@ extra_index: u32 = 0,...@@ -33,7 +33,8 @@ extra_index: u32 = 0,
33pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {33pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
34 const file_ptr = symbol.file(elf_file).?;34 const file_ptr = symbol.file(elf_file).?;
35 if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;35 if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;
36 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and36 return !symbol.flags.import and symbol.atom(elf_file) == null and
37 symbol.mergeSubsection(elf_file) == null and symbol.outputShndx() == null and
37 file_ptr != .linker_defined;38 file_ptr != .linker_defined;
38}39}
3940
...@@ -70,6 +71,12 @@ pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {...@@ -70,6 +71,12 @@ pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
70 return elf_file.atom(symbol.atom_index);71 return elf_file.atom(symbol.atom_index);
71}72}
7273
74pub 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
73pub fn file(symbol: Symbol, elf_file: *Elf) ?File {80pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
74 return elf_file.file(symbol.file_index);81 return elf_file.file(symbol.file_index);
75}82}
...@@ -92,7 +99,11 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {...@@ -92,7 +99,11 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
92 return file_ptr.symbolRank(sym, in_archive);99 return file_ptr.symbolRank(sym, in_archive);
93}100}
94101
95pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) u64 {102pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 {
103 if (symbol.mergeSubsection(elf_file)) |msub| {
104 if (!msub.alive) return 0;
105 return msub.address(elf_file) + symbol.value;
106 }
96 if (symbol.flags.has_copy_rel) {107 if (symbol.flags.has_copy_rel) {
97 return symbol.copyRelAddress(elf_file);108 return symbol.copyRelAddress(elf_file);
98 }109 }
...@@ -108,19 +119,23 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf...@@ -108,19 +119,23 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
108 if (!atom_ptr.flags.alive) {119 if (!atom_ptr.flags.alive) {
109 if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {120 if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {
110 const sym_name = symbol.name(elf_file);121 const sym_name = symbol.name(elf_file);
122 const sh_addr, const sh_size = blk: {
123 const shndx = elf_file.eh_frame_section_index orelse break :blk .{ 0, 0 };
124 const shdr = elf_file.shdrs.items[shndx];
125 break :blk .{ shdr.sh_addr, shdr.sh_size };
126 };
111 if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or127 if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or
112 mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or128 mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or
113 mem.startsWith(u8, sym_name, ".eh_frame_seg") or129 mem.startsWith(u8, sym_name, ".eh_frame_seg") or
114 symbol.elfSym(elf_file).st_type() == elf.STT_SECTION)130 symbol.elfSym(elf_file).st_type() == elf.STT_SECTION)
115 {131 {
116 return elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr;132 return @intCast(sh_addr);
117 }133 }
118134
119 if (mem.startsWith(u8, sym_name, "__FRAME_END__") or135 if (mem.startsWith(u8, sym_name, "__FRAME_END__") or
120 mem.startsWith(u8, sym_name, "__EH_FRAME_LIST_END__"))136 mem.startsWith(u8, sym_name, "__EH_FRAME_LIST_END__"))
121 {137 {
122 const shdr = elf_file.shdrs.items[elf_file.eh_frame_section_index.?];138 return @intCast(sh_addr + sh_size);
123 return shdr.sh_addr + shdr.sh_size;
124 }139 }
125140
126 // TODO I think we potentially should error here141 // TODO I think we potentially should error here
...@@ -143,65 +158,57 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {...@@ -143,65 +158,57 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
143 return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;158 return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
144}159}
145160
146pub fn setOutputSymtabIndex(symbol: *Symbol, index: u32, elf_file: *Elf) !void {161pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {
147 if (symbol.extra(elf_file)) |extras| {
148 var new_extras = extras;
149 new_extras.symtab = index;
150 symbol.setExtra(new_extras, elf_file);
151 } else try symbol.addExtra(.{ .symtab = index }, elf_file);
152}
153
154pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
155 if (!symbol.flags.has_got) return 0;162 if (!symbol.flags.has_got) return 0;
156 const extras = symbol.extra(elf_file).?;163 const extras = symbol.extra(elf_file).?;
157 const entry = elf_file.got.entries.items[extras.got];164 const entry = elf_file.got.entries.items[extras.got];
158 return entry.address(elf_file);165 return entry.address(elf_file);
159}166}
160167
161pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) u64 {168pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
162 if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;169 if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;
163 const extras = symbol.extra(elf_file).?;170 const extras = symbol.extra(elf_file).?;
164 const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];171 const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];
165 const cpu_arch = elf_file.getTarget().cpu.arch;172 const cpu_arch = elf_file.getTarget().cpu.arch;
166 return shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch);173 return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch));
167}174}
168175
169pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 {176pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {
170 if (!symbol.flags.has_plt) return 0;177 if (!symbol.flags.has_plt) return 0;
171 const extras = symbol.extra(elf_file).?;178 const extras = symbol.extra(elf_file).?;
172 const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];179 const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];
173 const cpu_arch = elf_file.getTarget().cpu.arch;180 const cpu_arch = elf_file.getTarget().cpu.arch;
174 return shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch);181 return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch));
175}182}
176183
177pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) u64 {184pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 {
178 if (!symbol.flags.has_plt) return 0;185 if (!symbol.flags.has_plt) return 0;
179 const extras = symbol.extra(elf_file).?;186 const extras = symbol.extra(elf_file).?;
180 const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];187 const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];
181 return shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size;188 return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size);
182}189}
183190
184pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) u64 {191pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 {
185 if (!symbol.flags.has_copy_rel) return 0;192 if (!symbol.flags.has_copy_rel) return 0;
186 const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?];193 const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?];
187 return shdr.sh_addr + symbol.value;194 return @as(i64, @intCast(shdr.sh_addr)) + symbol.value;
188}195}
189196
190pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 {197pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 {
191 if (!symbol.flags.has_tlsgd) return 0;198 if (!symbol.flags.has_tlsgd) return 0;
192 const extras = symbol.extra(elf_file).?;199 const extras = symbol.extra(elf_file).?;
193 const entry = elf_file.got.entries.items[extras.tlsgd];200 const entry = elf_file.got.entries.items[extras.tlsgd];
194 return entry.address(elf_file);201 return entry.address(elf_file);
195}202}
196203
197pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) u64 {204pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 {
198 if (!symbol.flags.has_gottp) return 0;205 if (!symbol.flags.has_gottp) return 0;
199 const extras = symbol.extra(elf_file).?;206 const extras = symbol.extra(elf_file).?;
200 const entry = elf_file.got.entries.items[extras.gottp];207 const entry = elf_file.got.entries.items[extras.gottp];
201 return entry.address(elf_file);208 return entry.address(elf_file);
202}209}
203210
204pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 {211pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
205 if (!symbol.flags.has_tlsdesc) return 0;212 if (!symbol.flags.has_tlsdesc) return 0;
206 const extras = symbol.extra(elf_file).?;213 const extras = symbol.extra(elf_file).?;
207 const entry = elf_file.got.entries.items[extras.tlsdesc];214 const entry = elf_file.got.entries.items[extras.tlsdesc];
...@@ -221,7 +228,7 @@ pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *E...@@ -221,7 +228,7 @@ pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *E
221 return .{ .found_existing = false, .index = index };228 return .{ .found_existing = false, .index = index };
222}229}
223230
224pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) u64 {231pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
225 if (!symbol.flags.has_zig_got) return 0;232 if (!symbol.flags.has_zig_got) return 0;
226 const extras = symbol.extra(elf_file).?;233 const extras = symbol.extra(elf_file).?;
227 return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);234 return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
...@@ -240,8 +247,31 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {...@@ -240,8 +247,31 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
240 @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value)));247 @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value)));
241}248}
242249
243pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void {250const AddExtraOpts = struct {
244 symbol.extra_index = try elf_file.addSymbolExtra(extras);251 got: ?u32 = null,
252 plt: ?u32 = null,
253 plt_got: ?u32 = null,
254 dynamic: ?u32 = null,
255 symtab: ?u32 = null,
256 copy_rel: ?u32 = null,
257 tlsgd: ?u32 = null,
258 gottp: ?u32 = null,
259 tlsdesc: ?u32 = null,
260 zig_got: ?u32 = null,
261 subsection: ?u32 = null,
262};
263
264pub 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}
246276
247pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {277pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {
...@@ -266,6 +296,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -266,6 +296,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
266 if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.copy_rel_section_index.?);296 if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.copy_rel_section_index.?);
267 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;297 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
268 if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;298 if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
299 if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index);
269 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;300 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
270 break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF);301 break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF);
271 };302 };
...@@ -284,7 +315,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -284,7 +315,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
284 out.st_info = (st_bind << 4) | st_type;315 out.st_info = (st_bind << 4) | st_type;
285 out.st_other = esym.st_other;316 out.st_other = esym.st_other;
286 out.st_shndx = st_shndx;317 out.st_shndx = st_shndx;
287 out.st_value = st_value;318 out.st_value = @intCast(st_value);
288 out.st_size = esym.st_size;319 out.st_size = esym.st_size;
289}320}
290321
...@@ -436,6 +467,9 @@ pub const Flags = packed struct {...@@ -436,6 +467,9 @@ pub const Flags = packed struct {
436 /// TODO this is really not needed if only we operated on esyms between467 /// TODO this is really not needed if only we operated on esyms between
437 /// codegen and ZigObject.468 /// codegen and ZigObject.
438 is_tls: bool = false,469 is_tls: bool = false,
470
471 /// Whether the symbol is a merge subsection.
472 merge_subsection: bool = false,
439};473};
440474
441pub const Extra = struct {475pub const Extra = struct {
...@@ -449,6 +483,7 @@ pub const Extra = struct {...@@ -449,6 +483,7 @@ pub const Extra = struct {
449 gottp: u32 = 0,483 gottp: u32 = 0,
450 tlsdesc: u32 = 0,484 tlsdesc: u32 = 0,
451 zig_got: u32 = 0,485 zig_got: u32 = 0,
486 subsection: u32 = 0,
452};487};
453488
454pub const Index = u32;489pub const Index = u32;
...@@ -465,6 +500,7 @@ const File = @import("file.zig").File;...@@ -465,6 +500,7 @@ const File = @import("file.zig").File;
465const GotSection = synthetic_sections.GotSection;500const GotSection = synthetic_sections.GotSection;
466const GotPltSection = synthetic_sections.GotPltSection;501const GotPltSection = synthetic_sections.GotPltSection;
467const LinkerDefined = @import("LinkerDefined.zig");502const LinkerDefined = @import("LinkerDefined.zig");
503const MergeSubsection = @import("merge_section.zig").MergeSubsection;
468const Object = @import("Object.zig");504const Object = @import("Object.zig");
469const PltSection = synthetic_sections.PltSection;505const PltSection = synthetic_sections.PltSection;
470const PltGotSection = synthetic_sections.PltGotSection;506const PltGotSection = synthetic_sections.PltGotSection;
src/link/Elf/ZigObject.zig+14-14
...@@ -343,7 +343,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {...@@ -343,7 +343,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
343 atom.outputShndx().?343 atom.outputShndx().?
344 else344 else
345 elf.SHN_UNDEF;345 elf.SHN_UNDEF;
346 global.value = esym.st_value;346 global.value = @intCast(esym.st_value);
347 global.atom_index = atom_index;347 global.atom_index = atom_index;
348 global.esym_index = esym_index;348 global.esym_index = esym_index;
349 global.file_index = self.index;349 global.file_index = self.index;
...@@ -566,7 +566,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -566,7 +566,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
566 else => {},566 else => {},
567 }567 }
568 local.flags.output_symtab = true;568 local.flags.output_symtab = true;
569 try local.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file);569 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
570 self.output_symtab_ctx.nlocals += 1;570 self.output_symtab_ctx.nlocals += 1;
571 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;571 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
572 }572 }
...@@ -578,10 +578,10 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -578,10 +578,10 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
578 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;578 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
579 global.flags.output_symtab = true;579 global.flags.output_symtab = true;
580 if (global.isLocal(elf_file)) {580 if (global.isLocal(elf_file)) {
581 try global.setOutputSymtabIndex(self.output_symtab_ctx.nlocals, elf_file);581 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
582 self.output_symtab_ctx.nlocals += 1;582 self.output_symtab_ctx.nlocals += 1;
583 } else {583 } else {
584 try global.setOutputSymtabIndex(self.output_symtab_ctx.nglobals, elf_file);584 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
585 self.output_symtab_ctx.nglobals += 1;585 self.output_symtab_ctx.nglobals += 1;
586 }586 }
587 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;587 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
...@@ -631,7 +631,7 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8...@@ -631,7 +631,7 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
631 return code;631 return code;
632 }632 }
633633
634 const file_offset = shdr.sh_offset + atom.value;634 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value));
635 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;635 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
636 const code = try gpa.alloc(u8, size);636 const code = try gpa.alloc(u8, size);
637 errdefer gpa.free(code);637 errdefer gpa.free(code);
...@@ -659,7 +659,7 @@ pub fn getDeclVAddr(...@@ -659,7 +659,7 @@ pub fn getDeclVAddr(
659 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type,659 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type,
660 .r_addend = reloc_info.addend,660 .r_addend = reloc_info.addend,
661 });661 });
662 return vaddr;662 return @intCast(vaddr);
663}663}
664664
665pub fn getAnonDeclVAddr(665pub fn getAnonDeclVAddr(
...@@ -678,7 +678,7 @@ pub fn getAnonDeclVAddr(...@@ -678,7 +678,7 @@ pub fn getAnonDeclVAddr(
678 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type,678 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type,
679 .r_addend = reloc_info.addend,679 .r_addend = reloc_info.addend,
680 });680 });
681 return vaddr;681 return @intCast(vaddr);
682}682}
683683
684pub fn lowerAnonDecl(684pub fn lowerAnonDecl(
...@@ -929,7 +929,7 @@ fn updateDeclCode(...@@ -929,7 +929,7 @@ fn updateDeclCode(
929929
930 if (old_size > 0 and elf_file.base.child_pid == null) {930 if (old_size > 0 and elf_file.base.child_pid == null) {
931 const capacity = atom_ptr.capacity(elf_file);931 const capacity = atom_ptr.capacity(elf_file);
932 const need_realloc = code.len > capacity or !required_alignment.check(atom_ptr.value);932 const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
933 if (need_realloc) {933 if (need_realloc) {
934 try atom_ptr.grow(elf_file);934 try atom_ptr.grow(elf_file);
935 log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom_ptr.value });935 log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom_ptr.value });
...@@ -984,7 +984,7 @@ fn updateDeclCode(...@@ -984,7 +984,7 @@ fn updateDeclCode(
984984
985 const shdr = elf_file.shdrs.items[shdr_index];985 const shdr = elf_file.shdrs.items[shdr_index];
986 if (shdr.sh_type != elf.SHT_NOBITS) {986 if (shdr.sh_type != elf.SHT_NOBITS) {
987 const file_offset = shdr.sh_offset + atom_ptr.value;987 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
988 try elf_file.base.file.?.pwriteAll(code, file_offset);988 try elf_file.base.file.?.pwriteAll(code, file_offset);
989 }989 }
990}990}
...@@ -1107,7 +1107,7 @@ pub fn updateFunc(...@@ -1107,7 +1107,7 @@ pub fn updateFunc(
1107 try self.dwarf.?.commitDeclState(1107 try self.dwarf.?.commitDeclState(
1108 mod,1108 mod,
1109 decl_index,1109 decl_index,
1110 sym.address(.{}, elf_file),1110 @intCast(sym.address(.{}, elf_file)),
1111 sym.atom(elf_file).?.size,1111 sym.atom(elf_file).?.size,
1112 ds,1112 ds,
1113 );1113 );
...@@ -1186,7 +1186,7 @@ pub fn updateDecl(...@@ -1186,7 +1186,7 @@ pub fn updateDecl(
1186 try self.dwarf.?.commitDeclState(1186 try self.dwarf.?.commitDeclState(
1187 mod,1187 mod,
1188 decl_index,1188 decl_index,
1189 sym.address(.{}, elf_file),1189 @intCast(sym.address(.{}, elf_file)),
1190 sym.atom(elf_file).?.size,1190 sym.atom(elf_file).?.size,
1191 ds,1191 ds,
1192 );1192 );
...@@ -1275,7 +1275,7 @@ fn updateLazySymbol(...@@ -1275,7 +1275,7 @@ fn updateLazySymbol(
1275 }1275 }
12761276
1277 const shdr = elf_file.shdrs.items[output_section_index];1277 const shdr = elf_file.shdrs.items[output_section_index];
1278 const file_offset = shdr.sh_offset + atom_ptr.value;1278 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1279 try elf_file.base.file.?.pwriteAll(code, file_offset);1279 try elf_file.base.file.?.pwriteAll(code, file_offset);
1280}1280}
12811281
...@@ -1373,7 +1373,7 @@ fn lowerConst(...@@ -1373,7 +1373,7 @@ fn lowerConst(
1373 local_esym.st_value = 0;1373 local_esym.st_value = 0;
13741374
1375 const shdr = elf_file.shdrs.items[output_section_index];1375 const shdr = elf_file.shdrs.items[output_section_index];
1376 const file_offset = shdr.sh_offset + atom_ptr.value;1376 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1377 try elf_file.base.file.?.pwriteAll(code, file_offset);1377 try elf_file.base.file.?.pwriteAll(code, file_offset);
13781378
1379 return .{ .ok = sym_index };1379 return .{ .ok = sym_index };
...@@ -1457,7 +1457,7 @@ pub fn updateExports(...@@ -1457,7 +1457,7 @@ pub fn updateExports(
14571457
1458 const actual_esym_index = global_esym_index & symbol_mask;1458 const actual_esym_index = global_esym_index & symbol_mask;
1459 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];1459 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];
1460 global_esym.st_value = elf_file.symbol(sym_index).value;1460 global_esym.st_value = @intCast(elf_file.symbol(sym_index).value);
1461 global_esym.st_shndx = esym.st_shndx;1461 global_esym.st_shndx = esym.st_shndx;
1462 global_esym.st_info = (stb_bits << 4) | stt_bits;1462 global_esym.st_info = (stb_bits << 4) | stt_bits;
1463 global_esym.st_name = name_off;1463 global_esym.st_name = name_off;
src/link/Elf/gc.zig+8
...@@ -68,6 +68,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil...@@ -68,6 +68,10 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
68}68}
6969
70fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {70fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
71 if (sym.mergeSubsection(elf_file)) |msub| {
72 msub.alive = true;
73 return;
74 }
71 const atom = sym.atom(elf_file) orelse return;75 const atom = sym.atom(elf_file) orelse return;
72 if (markAtom(atom)) try roots.append(atom);76 if (markAtom(atom)) try roots.append(atom);
73}77}
...@@ -96,6 +100,10 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -96,6 +100,10 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
96100
97 for (atom.relocs(elf_file)) |rel| {101 for (atom.relocs(elf_file)) |rel| {
98 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));102 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
103 if (target_sym.mergeSubsection(elf_file)) |msub| {
104 msub.alive = true;
105 continue;
106 }
99 const target_atom = target_sym.atom(elf_file) orelse continue;107 const target_atom = target_sym.atom(elf_file) orelse continue;
100 target_atom.flags.alive = true;108 target_atom.flags.alive = true;
101 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });109 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
src/link/Elf/merge_section.zig created+285
...@@ -0,0 +1,285 @@
1pub 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
165pub 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
233pub 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
277const String = struct { pos: u32, len: u32 };
278
279const assert = std.debug.assert;
280const mem = std.mem;
281const std = @import("std");
282
283const Allocator = mem.Allocator;
284const Atom = @import("Atom.zig");
285const Elf = @import("../Elf.zig");
src/link/Elf/relocatable.zig+13-2
...@@ -34,12 +34,16 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -34,12 +34,16 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
34 // First, we flush relocatable object file generated with our backends.34 // First, we flush relocatable object file generated with our backends.
35 if (elf_file.zigObjectPtr()) |zig_object| {35 if (elf_file.zigObjectPtr()) |zig_object| {
36 zig_object.resolveSymbols(elf_file);36 zig_object.resolveSymbols(elf_file);
37 try elf_file.addCommentString();
38 try elf_file.finalizeMergeSections();
37 zig_object.claimUnresolvedObject(elf_file);39 zig_object.claimUnresolvedObject(elf_file);
3840
41 try elf_file.initMergeSections();
39 try elf_file.initSymtab();42 try elf_file.initSymtab();
40 try elf_file.initShStrtab();43 try elf_file.initShStrtab();
41 try elf_file.sortShdrs();44 try elf_file.sortShdrs();
42 try zig_object.addAtomsToRelaSections(elf_file);45 try zig_object.addAtomsToRelaSections(elf_file);
46 try elf_file.updateMergeSectionSizes();
43 try updateSectionSizes(elf_file);47 try updateSectionSizes(elf_file);
4448
45 try allocateAllocSections(elf_file);49 try allocateAllocSections(elf_file);
...@@ -49,6 +53,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -49,6 +53,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
49 state_log.debug("{}", .{elf_file.dumpState()});53 state_log.debug("{}", .{elf_file.dumpState()});
50 }54 }
5155
56 try elf_file.writeMergeSections();
52 try writeSyntheticSections(elf_file);57 try writeSyntheticSections(elf_file);
53 try elf_file.writeShdrTable();58 try elf_file.writeShdrTable();
54 try elf_file.writeElfHeader();59 try elf_file.writeElfHeader();
...@@ -179,9 +184,13 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -179,9 +184,13 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
179 // input Object files.184 // input Object files.
180 elf_file.resolveSymbols();185 elf_file.resolveSymbols();
181 elf_file.markEhFrameAtomsDead();186 elf_file.markEhFrameAtomsDead();
187 try elf_file.resolveMergeSections();
188 try elf_file.addCommentString();
189 try elf_file.finalizeMergeSections();
182 claimUnresolved(elf_file);190 claimUnresolved(elf_file);
183191
184 try initSections(elf_file);192 try initSections(elf_file);
193 try elf_file.initMergeSections();
185 try elf_file.sortShdrs();194 try elf_file.sortShdrs();
186 if (elf_file.zigObjectPtr()) |zig_object| {195 if (elf_file.zigObjectPtr()) |zig_object| {
187 try zig_object.addAtomsToRelaSections(elf_file);196 try zig_object.addAtomsToRelaSections(elf_file);
...@@ -191,6 +200,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -191,6 +200,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
191 try object.addAtomsToOutputSections(elf_file);200 try object.addAtomsToOutputSections(elf_file);
192 try object.addAtomsToRelaSections(elf_file);201 try object.addAtomsToRelaSections(elf_file);
193 }202 }
203 try elf_file.updateMergeSectionSizes();
194 try updateSectionSizes(elf_file);204 try updateSectionSizes(elf_file);
195205
196 try allocateAllocSections(elf_file);206 try allocateAllocSections(elf_file);
...@@ -201,6 +211,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -201,6 +211,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
201 }211 }
202212
203 try writeAtoms(elf_file);213 try writeAtoms(elf_file);
214 try elf_file.writeMergeSections();
204 try writeSyntheticSections(elf_file);215 try writeSyntheticSections(elf_file);
205 try elf_file.writeShdrTable();216 try elf_file.writeShdrTable();
206 try elf_file.writeElfHeader();217 try elf_file.writeElfHeader();
...@@ -328,7 +339,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {...@@ -328,7 +339,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {
328 if (!atom_ptr.flags.alive) continue;339 if (!atom_ptr.flags.alive) continue;
329 const offset = atom_ptr.alignment.forward(shdr.sh_size);340 const offset = atom_ptr.alignment.forward(shdr.sh_size);
330 const padding = offset - shdr.sh_size;341 const padding = offset - shdr.sh_size;
331 atom_ptr.value = offset;342 atom_ptr.value = @intCast(offset);
332 shdr.sh_size += padding + atom_ptr.size;343 shdr.sh_size += padding + atom_ptr.size;
333 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);344 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
334 }345 }
...@@ -434,7 +445,7 @@ fn writeAtoms(elf_file: *Elf) !void {...@@ -434,7 +445,7 @@ fn writeAtoms(elf_file: *Elf) !void {
434 const atom_ptr = elf_file.atom(atom_index).?;445 const atom_ptr = elf_file.atom(atom_index).?;
435 assert(atom_ptr.flags.alive);446 assert(atom_ptr.flags.alive);
436447
437 const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse448 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
438 return error.Overflow;449 return error.Overflow;
439 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;450 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
440451
src/link/Elf/synthetic_sections.zig+47-85
...@@ -259,11 +259,7 @@ pub const ZigGotSection = struct {...@@ -259,11 +259,7 @@ pub const ZigGotSection = struct {
259 if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {259 if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
260 zig_got.flags.needs_rela = true;260 zig_got.flags.needs_rela = true;
261 }261 }
262 if (symbol.extra(elf_file)) |extra| {262 try symbol.addExtra(.{ .zig_got = index }, elf_file);
263 var new_extra = extra;
264 new_extra.zig_got = index;
265 symbol.setExtra(new_extra, elf_file);
266 } else try symbol.addExtra(.{ .zig_got = index }, elf_file);
267 return index;263 return index;
268 }264 }
269265
...@@ -274,11 +270,11 @@ pub const ZigGotSection = struct {...@@ -274,11 +270,11 @@ pub const ZigGotSection = struct {
274 return shdr.sh_offset + @as(u64, entry_size) * index;270 return shdr.sh_offset + @as(u64, entry_size) * index;
275 }271 }
276272
277 pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 {273 pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 {
278 _ = zig_got;274 _ = zig_got;
279 const entry_size = elf_file.archPtrWidthBytes();275 const entry_size = elf_file.archPtrWidthBytes();
280 const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];276 const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];
281 return shdr.sh_addr + @as(u64, entry_size) * index;277 return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index;
282 }278 }
283279
284 pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize {280 pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize {
...@@ -295,23 +291,23 @@ pub const ZigGotSection = struct {...@@ -295,23 +291,23 @@ pub const ZigGotSection = struct {
295 const target = elf_file.getTarget();291 const target = elf_file.getTarget();
296 const endian = target.cpu.arch.endian();292 const endian = target.cpu.arch.endian();
297 const off = zig_got.entryOffset(index, elf_file);293 const off = zig_got.entryOffset(index, elf_file);
298 const vaddr = zig_got.entryAddress(index, elf_file);294 const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));
299 const entry = zig_got.entries.items[index];295 const entry = zig_got.entries.items[index];
300 const value = elf_file.symbol(entry).address(.{}, elf_file);296 const value = elf_file.symbol(entry).address(.{}, elf_file);
301 switch (entry_size) {297 switch (entry_size) {
302 2 => {298 2 => {
303 var buf: [2]u8 = undefined;299 var buf: [2]u8 = undefined;
304 std.mem.writeInt(u16, &buf, @as(u16, @intCast(value)), endian);300 std.mem.writeInt(u16, &buf, @intCast(value), endian);
305 try elf_file.base.file.?.pwriteAll(&buf, off);301 try elf_file.base.file.?.pwriteAll(&buf, off);
306 },302 },
307 4 => {303 4 => {
308 var buf: [4]u8 = undefined;304 var buf: [4]u8 = undefined;
309 std.mem.writeInt(u32, &buf, @as(u32, @intCast(value)), endian);305 std.mem.writeInt(u32, &buf, @intCast(value), endian);
310 try elf_file.base.file.?.pwriteAll(&buf, off);306 try elf_file.base.file.?.pwriteAll(&buf, off);
311 },307 },
312 8 => {308 8 => {
313 var buf: [8]u8 = undefined;309 var buf: [8]u8 = undefined;
314 std.mem.writeInt(u64, &buf, value, endian);310 std.mem.writeInt(u64, &buf, @intCast(value), endian);
315 try elf_file.base.file.?.pwriteAll(&buf, off);311 try elf_file.base.file.?.pwriteAll(&buf, off);
316312
317 if (elf_file.base.child_pid) |pid| {313 if (elf_file.base.child_pid) |pid| {
...@@ -360,9 +356,9 @@ pub const ZigGotSection = struct {...@@ -360,9 +356,9 @@ pub const ZigGotSection = struct {
360 const symbol = elf_file.symbol(entry);356 const symbol = elf_file.symbol(entry);
361 const offset = symbol.zigGotAddress(elf_file);357 const offset = symbol.zigGotAddress(elf_file);
362 elf_file.addRelaDynAssumeCapacity(.{358 elf_file.addRelaDynAssumeCapacity(.{
363 .offset = offset,359 .offset = @intCast(offset),
364 .type = relocation.encode(.rel, cpu_arch),360 .type = relocation.encode(.rel, cpu_arch),
365 .addend = @intCast(symbol.address(.{ .plt = false }, elf_file)),361 .addend = symbol.address(.{ .plt = false }, elf_file),
366 });362 });
367 }363 }
368 }364 }
...@@ -390,7 +386,7 @@ pub const ZigGotSection = struct {...@@ -390,7 +386,7 @@ pub const ZigGotSection = struct {
390 .st_info = elf.STT_OBJECT,386 .st_info = elf.STT_OBJECT,
391 .st_other = 0,387 .st_other = 0,
392 .st_shndx = @intCast(elf_file.zig_got_section_index.?),388 .st_shndx = @intCast(elf_file.zig_got_section_index.?),
393 .st_value = st_value,389 .st_value = @intCast(st_value),
394 .st_size = st_size,390 .st_size = st_size,
395 };391 };
396 }392 }
...@@ -461,10 +457,10 @@ pub const GotSection = struct {...@@ -461,10 +457,10 @@ pub const GotSection = struct {
461 };457 };
462 }458 }
463459
464 pub fn address(entry: Entry, elf_file: *Elf) u64 {460 pub fn address(entry: Entry, elf_file: *Elf) i64 {
465 const ptr_bytes = @as(u64, elf_file.archPtrWidthBytes());461 const ptr_bytes = elf_file.archPtrWidthBytes();
466 const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?];462 const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?];
467 return shdr.sh_addr + @as(u64, entry.cell_index) * ptr_bytes;463 return @as(i64, @intCast(shdr.sh_addr)) + entry.cell_index * ptr_bytes;
468 }464 }
469 };465 };
470466
...@@ -499,11 +495,7 @@ pub const GotSection = struct {...@@ -499,11 +495,7 @@ pub const GotSection = struct {
499 {495 {
500 got.flags.needs_rela = true;496 got.flags.needs_rela = true;
501 }497 }
502 if (symbol.extra(elf_file)) |extra| {498 try symbol.addExtra(.{ .got = index }, elf_file);
503 var new_extra = extra;
504 new_extra.got = index;
505 symbol.setExtra(new_extra, elf_file);
506 } else try symbol.addExtra(.{ .got = index }, elf_file);
507 return index;499 return index;
508 }500 }
509501
...@@ -529,11 +521,7 @@ pub const GotSection = struct {...@@ -529,11 +521,7 @@ pub const GotSection = struct {
529 const symbol = elf_file.symbol(sym_index);521 const symbol = elf_file.symbol(sym_index);
530 symbol.flags.has_tlsgd = true;522 symbol.flags.has_tlsgd = true;
531 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;523 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
532 if (symbol.extra(elf_file)) |extra| {524 try symbol.addExtra(.{ .tlsgd = index }, elf_file);
533 var new_extra = extra;
534 new_extra.tlsgd = index;
535 symbol.setExtra(new_extra, elf_file);
536 } else try symbol.addExtra(.{ .tlsgd = index }, elf_file);
537 }525 }
538526
539 pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {527 pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
...@@ -546,11 +534,7 @@ pub const GotSection = struct {...@@ -546,11 +534,7 @@ pub const GotSection = struct {
546 const symbol = elf_file.symbol(sym_index);534 const symbol = elf_file.symbol(sym_index);
547 symbol.flags.has_gottp = true;535 symbol.flags.has_gottp = true;
548 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;536 if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
549 if (symbol.extra(elf_file)) |extra| {537 try symbol.addExtra(.{ .gottp = index }, elf_file);
550 var new_extra = extra;
551 new_extra.gottp = index;
552 symbol.setExtra(new_extra, elf_file);
553 } else try symbol.addExtra(.{ .gottp = index }, elf_file);
554 }538 }
555539
556 pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {540 pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
...@@ -563,11 +547,7 @@ pub const GotSection = struct {...@@ -563,11 +547,7 @@ pub const GotSection = struct {
563 const symbol = elf_file.symbol(sym_index);547 const symbol = elf_file.symbol(sym_index);
564 symbol.flags.has_tlsdesc = true;548 symbol.flags.has_tlsdesc = true;
565 got.flags.needs_rela = true;549 got.flags.needs_rela = true;
566 if (symbol.extra(elf_file)) |extra| {550 try symbol.addExtra(.{ .tlsdesc = index }, elf_file);
567 var new_extra = extra;
568 new_extra.tlsdesc = index;
569 symbol.setExtra(new_extra, elf_file);
570 } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file);
571 }551 }
572552
573 pub fn size(got: GotSection, elf_file: *Elf) usize {553 pub fn size(got: GotSection, elf_file: *Elf) usize {
...@@ -628,8 +608,7 @@ pub const GotSection = struct {...@@ -628,8 +608,7 @@ pub const GotSection = struct {
628 0;608 0;
629 try writeInt(offset, elf_file, writer);609 try writeInt(offset, elf_file, writer);
630 } else {610 } else {
631 const offset = @as(i64, @intCast(symbol.?.address(.{}, elf_file))) -611 const offset = symbol.?.address(.{}, elf_file) - elf_file.tpAddress();
632 @as(i64, @intCast(elf_file.tpAddress()));
633 try writeInt(offset, elf_file, writer);612 try writeInt(offset, elf_file, writer);
634 }613 }
635 },614 },
...@@ -640,7 +619,7 @@ pub const GotSection = struct {...@@ -640,7 +619,7 @@ pub const GotSection = struct {
640 } else {619 } else {
641 try writeInt(0, elf_file, writer);620 try writeInt(0, elf_file, writer);
642 const offset = if (apply_relocs)621 const offset = if (apply_relocs)
643 @as(i64, @intCast(symbol.?.address(.{}, elf_file))) - @as(i64, @intCast(elf_file.tlsAddress()))622 symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()
644 else623 else
645 0;624 0;
646 try writeInt(offset, elf_file, writer);625 try writeInt(offset, elf_file, writer);
...@@ -666,7 +645,7 @@ pub const GotSection = struct {...@@ -666,7 +645,7 @@ pub const GotSection = struct {
666645
667 switch (entry.tag) {646 switch (entry.tag) {
668 .got => {647 .got => {
669 const offset = symbol.?.gotAddress(elf_file);648 const offset: u64 = @intCast(symbol.?.gotAddress(elf_file));
670 if (symbol.?.flags.import) {649 if (symbol.?.flags.import) {
671 elf_file.addRelaDynAssumeCapacity(.{650 elf_file.addRelaDynAssumeCapacity(.{
672 .offset = offset,651 .offset = offset,
...@@ -679,7 +658,7 @@ pub const GotSection = struct {...@@ -679,7 +658,7 @@ pub const GotSection = struct {
679 elf_file.addRelaDynAssumeCapacity(.{658 elf_file.addRelaDynAssumeCapacity(.{
680 .offset = offset,659 .offset = offset,
681 .type = relocation.encode(.irel, cpu_arch),660 .type = relocation.encode(.irel, cpu_arch),
682 .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)),661 .addend = symbol.?.address(.{ .plt = false }, elf_file),
683 });662 });
684 continue;663 continue;
685 }664 }
...@@ -689,14 +668,14 @@ pub const GotSection = struct {...@@ -689,14 +668,14 @@ pub const GotSection = struct {
689 elf_file.addRelaDynAssumeCapacity(.{668 elf_file.addRelaDynAssumeCapacity(.{
690 .offset = offset,669 .offset = offset,
691 .type = relocation.encode(.rel, cpu_arch),670 .type = relocation.encode(.rel, cpu_arch),
692 .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)),671 .addend = symbol.?.address(.{ .plt = false }, elf_file),
693 });672 });
694 }673 }
695 },674 },
696675
697 .tlsld => {676 .tlsld => {
698 if (is_dyn_lib) {677 if (is_dyn_lib) {
699 const offset = entry.address(elf_file);678 const offset: u64 = @intCast(entry.address(elf_file));
700 elf_file.addRelaDynAssumeCapacity(.{679 elf_file.addRelaDynAssumeCapacity(.{
701 .offset = offset,680 .offset = offset,
702 .type = relocation.encode(.dtpmod, cpu_arch),681 .type = relocation.encode(.dtpmod, cpu_arch),
...@@ -705,7 +684,7 @@ pub const GotSection = struct {...@@ -705,7 +684,7 @@ pub const GotSection = struct {
705 },684 },
706685
707 .tlsgd => {686 .tlsgd => {
708 const offset = symbol.?.tlsGdAddress(elf_file);687 const offset: u64 = @intCast(symbol.?.tlsGdAddress(elf_file));
709 if (symbol.?.flags.import) {688 if (symbol.?.flags.import) {
710 elf_file.addRelaDynAssumeCapacity(.{689 elf_file.addRelaDynAssumeCapacity(.{
711 .offset = offset,690 .offset = offset,
...@@ -727,7 +706,7 @@ pub const GotSection = struct {...@@ -727,7 +706,7 @@ pub const GotSection = struct {
727 },706 },
728707
729 .gottp => {708 .gottp => {
730 const offset = symbol.?.gotTpAddress(elf_file);709 const offset: u64 = @intCast(symbol.?.gotTpAddress(elf_file));
731 if (symbol.?.flags.import) {710 if (symbol.?.flags.import) {
732 elf_file.addRelaDynAssumeCapacity(.{711 elf_file.addRelaDynAssumeCapacity(.{
733 .offset = offset,712 .offset = offset,
...@@ -738,18 +717,18 @@ pub const GotSection = struct {...@@ -738,18 +717,18 @@ pub const GotSection = struct {
738 elf_file.addRelaDynAssumeCapacity(.{717 elf_file.addRelaDynAssumeCapacity(.{
739 .offset = offset,718 .offset = offset,
740 .type = relocation.encode(.tpoff, cpu_arch),719 .type = relocation.encode(.tpoff, cpu_arch),
741 .addend = @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()),720 .addend = symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
742 });721 });
743 }722 }
744 },723 },
745724
746 .tlsdesc => {725 .tlsdesc => {
747 const offset = symbol.?.tlsDescAddress(elf_file);726 const offset: u64 = @intCast(symbol.?.tlsDescAddress(elf_file));
748 elf_file.addRelaDynAssumeCapacity(.{727 elf_file.addRelaDynAssumeCapacity(.{
749 .offset = offset,728 .offset = offset,
750 .sym = if (symbol.?.flags.import) extra.?.dynamic else 0,729 .sym = if (symbol.?.flags.import) extra.?.dynamic else 0,
751 .type = relocation.encode(.tlsdesc, cpu_arch),730 .type = relocation.encode(.tlsdesc, cpu_arch),
752 .addend = if (symbol.?.flags.import) 0 else @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()),731 .addend = if (symbol.?.flags.import) 0 else symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
753 });732 });
754 },733 },
755 }734 }
...@@ -826,7 +805,7 @@ pub const GotSection = struct {...@@ -826,7 +805,7 @@ pub const GotSection = struct {
826 .st_info = elf.STT_OBJECT,805 .st_info = elf.STT_OBJECT,
827 .st_other = 0,806 .st_other = 0,
828 .st_shndx = @intCast(elf_file.got_section_index.?),807 .st_shndx = @intCast(elf_file.got_section_index.?),
829 .st_value = st_value,808 .st_value = @intCast(st_value),
830 .st_size = st_size,809 .st_size = st_size,
831 };810 };
832 }811 }
...@@ -877,11 +856,7 @@ pub const PltSection = struct {...@@ -877,11 +856,7 @@ pub const PltSection = struct {
877 const index = @as(u32, @intCast(plt.symbols.items.len));856 const index = @as(u32, @intCast(plt.symbols.items.len));
878 const symbol = elf_file.symbol(sym_index);857 const symbol = elf_file.symbol(sym_index);
879 symbol.flags.has_plt = true;858 symbol.flags.has_plt = true;
880 if (symbol.extra(elf_file)) |extra| {859 try symbol.addExtra(.{ .plt = index }, elf_file);
881 var new_extra = extra;
882 new_extra.plt = index;
883 symbol.setExtra(new_extra, elf_file);
884 } else try symbol.addExtra(.{ .plt = index }, elf_file);
885 try plt.symbols.append(gpa, sym_index);860 try plt.symbols.append(gpa, sym_index);
886 }861 }
887862
...@@ -924,7 +899,7 @@ pub const PltSection = struct {...@@ -924,7 +899,7 @@ pub const PltSection = struct {
924 const sym = elf_file.symbol(sym_index);899 const sym = elf_file.symbol(sym_index);
925 assert(sym.flags.import);900 assert(sym.flags.import);
926 const extra = sym.extra(elf_file).?;901 const extra = sym.extra(elf_file).?;
927 const r_offset = sym.gotPltAddress(elf_file);902 const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));
928 const r_sym: u64 = extra.dynamic;903 const r_sym: u64 = extra.dynamic;
929 const r_type = relocation.encode(.jump_slot, cpu_arch);904 const r_type = relocation.encode(.jump_slot, cpu_arch);
930 elf_file.rela_plt.appendAssumeCapacity(.{905 elf_file.rela_plt.appendAssumeCapacity(.{
...@@ -960,7 +935,7 @@ pub const PltSection = struct {...@@ -960,7 +935,7 @@ pub const PltSection = struct {
960 .st_info = elf.STT_FUNC,935 .st_info = elf.STT_FUNC,
961 .st_other = 0,936 .st_other = 0,
962 .st_shndx = @intCast(elf_file.plt_section_index.?),937 .st_shndx = @intCast(elf_file.plt_section_index.?),
963 .st_value = sym.pltAddress(elf_file),938 .st_value = @intCast(sym.pltAddress(elf_file)),
964 .st_size = entrySize(cpu_arch),939 .st_size = entrySize(cpu_arch),
965 };940 };
966 }941 }
...@@ -1033,13 +1008,13 @@ pub const PltSection = struct {...@@ -1033,13 +1008,13 @@ pub const PltSection = struct {
1033 const aarch64 = struct {1008 const aarch64 = struct {
1034 fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {1009 fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {
1035 {1010 {
1036 const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr;1011 const plt_addr: i64 = @intCast(elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr);
1037 const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr;1012 const got_plt_addr: i64 = @intCast(elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr);
1038 // TODO: relax if possible1013 // TODO: relax if possible
1039 // .got.plt[2]1014 // .got.plt[2]
1040 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);1015 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
1041 const ldr_off = try math.divExact(u12, @truncate(got_plt_addr + 16), 8);1016 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8);
1042 const add_off: u12 = @truncate(got_plt_addr + 16);1017 const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
10431018
1044 const preamble = &[_]Instruction{1019 const preamble = &[_]Instruction{
1045 Instruction.stp(1020 Instruction.stp(
...@@ -1067,8 +1042,8 @@ pub const PltSection = struct {...@@ -1067,8 +1042,8 @@ pub const PltSection = struct {
1067 const target_addr = sym.gotPltAddress(elf_file);1042 const target_addr = sym.gotPltAddress(elf_file);
1068 const source_addr = sym.pltAddress(elf_file);1043 const source_addr = sym.pltAddress(elf_file);
1069 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);1044 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
1070 const ldr_off = try math.divExact(u12, @truncate(target_addr), 8);1045 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
1071 const add_off: u12 = @truncate(target_addr);1046 const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
1072 const insts = &[_]Instruction{1047 const insts = &[_]Instruction{
1073 Instruction.adrp(.x16, pages),1048 Instruction.adrp(.x16, pages),
1074 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),1049 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
...@@ -1101,7 +1076,7 @@ pub const GotPltSection = struct {...@@ -1101,7 +1076,7 @@ pub const GotPltSection = struct {
1101 {1076 {
1102 // [0]: _DYNAMIC1077 // [0]: _DYNAMIC
1103 const symbol = elf_file.symbol(elf_file.dynamic_index.?);1078 const symbol = elf_file.symbol(elf_file.dynamic_index.?);
1104 try writer.writeInt(u64, symbol.address(.{}, elf_file), .little);1079 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
1105 }1080 }
1106 // [1]: 0x01081 // [1]: 0x0
1107 // [2]: 0x01082 // [2]: 0x0
...@@ -1132,11 +1107,7 @@ pub const PltGotSection = struct {...@@ -1132,11 +1107,7 @@ pub const PltGotSection = struct {
1132 const symbol = elf_file.symbol(sym_index);1107 const symbol = elf_file.symbol(sym_index);
1133 symbol.flags.has_plt = true;1108 symbol.flags.has_plt = true;
1134 symbol.flags.has_got = true;1109 symbol.flags.has_got = true;
1135 if (symbol.extra(elf_file)) |extra| {1110 try symbol.addExtra(.{ .plt_got = index }, elf_file);
1136 var new_extra = extra;
1137 new_extra.plt_got = index;
1138 symbol.setExtra(new_extra, elf_file);
1139 } else try symbol.addExtra(.{ .plt_got = index }, elf_file);
1140 try plt_got.symbols.append(gpa, sym_index);1111 try plt_got.symbols.append(gpa, sym_index);
1141 }1112 }
11421113
...@@ -1181,7 +1152,7 @@ pub const PltGotSection = struct {...@@ -1181,7 +1152,7 @@ pub const PltGotSection = struct {
1181 .st_info = elf.STT_FUNC,1152 .st_info = elf.STT_FUNC,
1182 .st_other = 0,1153 .st_other = 0,
1183 .st_shndx = @intCast(elf_file.plt_got_section_index.?),1154 .st_shndx = @intCast(elf_file.plt_got_section_index.?),
1184 .st_value = sym.pltGotAddress(elf_file),1155 .st_value = @intCast(sym.pltGotAddress(elf_file)),
1185 .st_size = 16,1156 .st_size = 16,
1186 };1157 };
1187 }1158 }
...@@ -1212,7 +1183,7 @@ pub const PltGotSection = struct {...@@ -1212,7 +1183,7 @@ pub const PltGotSection = struct {
1212 const target_addr = sym.gotAddress(elf_file);1183 const target_addr = sym.gotAddress(elf_file);
1213 const source_addr = sym.pltGotAddress(elf_file);1184 const source_addr = sym.pltGotAddress(elf_file);
1214 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);1185 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
1215 const off = try math.divExact(u12, @truncate(target_addr), 8);1186 const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
1216 const insts = &[_]Instruction{1187 const insts = &[_]Instruction{
1217 Instruction.adrp(.x16, pages),1188 Instruction.adrp(.x16, pages),
1218 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),1189 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),
...@@ -1248,12 +1219,7 @@ pub const CopyRelSection = struct {...@@ -1248,12 +1219,7 @@ pub const CopyRelSection = struct {
1248 symbol.flags.@"export" = true;1219 symbol.flags.@"export" = true;
1249 symbol.flags.has_copy_rel = true;1220 symbol.flags.has_copy_rel = true;
1250 symbol.flags.weak = false;1221 symbol.flags.weak = false;
12511222 try symbol.addExtra(.{ .copy_rel = index }, elf_file);
1252 if (symbol.extra(elf_file)) |extra| {
1253 var new_extra = extra;
1254 new_extra.copy_rel = index;
1255 symbol.setExtra(new_extra, elf_file);
1256 } else try symbol.addExtra(.{ .copy_rel = index }, elf_file);
1257 try copy_rel.symbols.append(gpa, sym_index);1223 try copy_rel.symbols.append(gpa, sym_index);
12581224
1259 const shared_object = symbol.file(elf_file).?.shared_object;1225 const shared_object = symbol.file(elf_file).?.shared_object;
...@@ -1280,9 +1246,9 @@ pub const CopyRelSection = struct {...@@ -1280,9 +1246,9 @@ pub const CopyRelSection = struct {
1280 const symbol = elf_file.symbol(sym_index);1246 const symbol = elf_file.symbol(sym_index);
1281 const shared_object = symbol.file(elf_file).?.shared_object;1247 const shared_object = symbol.file(elf_file).?.shared_object;
1282 const alignment = try symbol.dsoAlignment(elf_file);1248 const alignment = try symbol.dsoAlignment(elf_file);
1283 symbol.value = mem.alignForward(u64, shdr.sh_size, alignment);1249 symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment));
1284 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);1250 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);
1285 shdr.sh_size = symbol.value + symbol.elfSym(elf_file).st_size;1251 shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size;
12861252
1287 const aliases = shared_object.symbolAliases(sym_index, elf_file);1253 const aliases = shared_object.symbolAliases(sym_index, elf_file);
1288 for (aliases) |alias| {1254 for (aliases) |alias| {
...@@ -1303,7 +1269,7 @@ pub const CopyRelSection = struct {...@@ -1303,7 +1269,7 @@ pub const CopyRelSection = struct {
1303 assert(sym.flags.import and sym.flags.has_copy_rel);1269 assert(sym.flags.import and sym.flags.has_copy_rel);
1304 const extra = sym.extra(elf_file).?;1270 const extra = sym.extra(elf_file).?;
1305 elf_file.addRelaDynAssumeCapacity(.{1271 elf_file.addRelaDynAssumeCapacity(.{
1306 .offset = sym.address(.{}, elf_file),1272 .offset = @intCast(sym.address(.{}, elf_file)),
1307 .sym = extra.dynamic,1273 .sym = extra.dynamic,
1308 .type = relocation.encode(.copy, cpu_arch),1274 .type = relocation.encode(.copy, cpu_arch),
1309 });1275 });
...@@ -1335,11 +1301,7 @@ pub const DynsymSection = struct {...@@ -1335,11 +1301,7 @@ pub const DynsymSection = struct {
1335 const index = @as(u32, @intCast(dynsym.entries.items.len + 1));1301 const index = @as(u32, @intCast(dynsym.entries.items.len + 1));
1336 const sym = elf_file.symbol(sym_index);1302 const sym = elf_file.symbol(sym_index);
1337 sym.flags.has_dynamic = true;1303 sym.flags.has_dynamic = true;
1338 if (sym.extra(elf_file)) |extra| {1304 try sym.addExtra(.{ .dynamic = index }, elf_file);
1339 var new_extra = extra;
1340 new_extra.dynamic = index;
1341 sym.setExtra(new_extra, elf_file);
1342 } else try sym.addExtra(.{ .dynamic = index }, elf_file);
1343 const off = try elf_file.insertDynString(sym.name(elf_file));1305 const off = try elf_file.insertDynString(sym.name(elf_file));
1344 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });1306 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
1345 }1307 }
src/link/Elf/thunks.zig+18-16
...@@ -7,7 +7,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -7,7 +7,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
7 assert(atoms.len > 0);7 assert(atoms.len > 0);
88
9 for (atoms) |atom_index| {9 for (atoms) |atom_index| {
10 elf_file.atom(atom_index).?.value = @bitCast(@as(i64, -1));10 elf_file.atom(atom_index).?.value = -1;
11 }11 }
1212
13 var i: usize = 0;13 var i: usize = 0;
...@@ -22,7 +22,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -22,7 +22,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
22 const atom_index = atoms[i];22 const atom_index = atoms[i];
23 const atom = elf_file.atom(atom_index).?;23 const atom = elf_file.atom(atom_index).?;
24 assert(atom.flags.alive);24 assert(atom.flags.alive);
25 if (atom.alignment.forward(shdr.sh_size) - start_atom.value >= max_distance) break;25 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
26 break;
26 atom.value = try advance(shdr, atom.size, atom.alignment);27 atom.value = try advance(shdr, atom.size, atom.alignment);
27 }28 }
2829
...@@ -50,7 +51,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -50,7 +51,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
50 };51 };
51 try thunk.symbols.put(gpa, target, {});52 try thunk.symbols.put(gpa, target, {});
52 }53 }
53 atom.thunk_index = thunk_index;54 try atom.addExtra(.{ .thunk = thunk_index }, elf_file);
55 atom.flags.thunk = true;
54 }56 }
5557
56 thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));58 thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
...@@ -59,12 +61,12 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -59,12 +61,12 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
59 }61 }
60}62}
6163
62fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 {64fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !i64 {
63 const offset = alignment.forward(shdr.sh_size);65 const offset = alignment.forward(shdr.sh_size);
64 const padding = offset - shdr.sh_size;66 const padding = offset - shdr.sh_size;
65 shdr.sh_size += padding + size;67 shdr.sh_size += padding + size;
66 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);68 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
67 return offset;69 return @intCast(offset);
68}70}
6971
70/// A branch will need an extender if its target is larger than72/// A branch will need an extender if its target is larger than
...@@ -78,7 +80,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {...@@ -78,7 +80,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {
78}80}
7981
80pub const Thunk = struct {82pub const Thunk = struct {
81 value: u64 = 0,83 value: i64 = 0,
82 output_section_index: u32 = 0,84 output_section_index: u32 = 0,
83 symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},85 symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
84 output_symtab_ctx: Elf.SymtabCtx = .{},86 output_symtab_ctx: Elf.SymtabCtx = .{},
...@@ -92,14 +94,14 @@ pub const Thunk = struct {...@@ -92,14 +94,14 @@ pub const Thunk = struct {
92 return thunk.symbols.keys().len * trampolineSize(cpu_arch);94 return thunk.symbols.keys().len * trampolineSize(cpu_arch);
93 }95 }
9496
95 pub fn address(thunk: Thunk, elf_file: *Elf) u64 {97 pub fn address(thunk: Thunk, elf_file: *Elf) i64 {
96 const shdr = elf_file.shdrs.items[thunk.output_section_index];98 const shdr = elf_file.shdrs.items[thunk.output_section_index];
97 return shdr.sh_addr + thunk.value;99 return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
98 }100 }
99101
100 pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) u64 {102 pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 {
101 const cpu_arch = elf_file.getTarget().cpu.arch;103 const cpu_arch = elf_file.getTarget().cpu.arch;
102 return thunk.address(elf_file) + thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch);104 return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch)));
103 }105 }
104106
105 pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {107 pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
...@@ -131,7 +133,7 @@ pub const Thunk = struct {...@@ -131,7 +133,7 @@ pub const Thunk = struct {
131 .st_info = elf.STT_FUNC,133 .st_info = elf.STT_FUNC,
132 .st_other = 0,134 .st_other = 0,
133 .st_shndx = @intCast(thunk.output_section_index),135 .st_shndx = @intCast(thunk.output_section_index),
134 .st_value = thunk.targetAddress(sym_index, elf_file),136 .st_value = @intCast(thunk.targetAddress(sym_index, elf_file)),
135 .st_size = trampolineSize(cpu_arch),137 .st_size = trampolineSize(cpu_arch),
136 };138 };
137 }139 }
...@@ -204,9 +206,9 @@ const aarch64 = struct {...@@ -204,9 +206,9 @@ const aarch64 = struct {
204 if (target.flags.has_plt) return false;206 if (target.flags.has_plt) return false;
205 if (atom.output_section_index != target.output_section_index) return false;207 if (atom.output_section_index != target.output_section_index) return false;
206 const target_atom = target.atom(elf_file).?;208 const target_atom = target.atom(elf_file).?;
207 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;209 if (target_atom.value == -1) return false;
208 const saddr = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset));210 const saddr = atom.address(elf_file) + @as(i64, @intCast(rel.r_offset));
209 const taddr: i64 = @intCast(target.address(.{}, elf_file));211 const taddr = target.address(.{}, elf_file);
210 _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false;212 _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false;
211 return true;213 return true;
212 }214 }
...@@ -214,11 +216,11 @@ const aarch64 = struct {...@@ -214,11 +216,11 @@ const aarch64 = struct {
214 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {216 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
215 for (thunk.symbols.keys(), 0..) |sym_index, i| {217 for (thunk.symbols.keys(), 0..) |sym_index, i| {
216 const sym = elf_file.symbol(sym_index);218 const sym = elf_file.symbol(sym_index);
217 const saddr = thunk.address(elf_file) + i * trampoline_size;219 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
218 const taddr = sym.address(.{}, elf_file);220 const taddr = sym.address(.{}, elf_file);
219 const pages = try util.calcNumberOfPages(saddr, taddr);221 const pages = try util.calcNumberOfPages(saddr, taddr);
220 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);222 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);
221 const off: u12 = @truncate(taddr);223 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));
222 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);224 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);
223 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);225 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);
224 }226 }
src/link/MachO/Atom.zig+1-1
...@@ -770,7 +770,7 @@ fn resolveRelocInner(...@@ -770,7 +770,7 @@ fn resolveRelocInner(
770 };770 };
771 break :target math.cast(u64, target) orelse return error.Overflow;771 break :target math.cast(u64, target) orelse return error.Overflow;
772 };772 };
773 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(source, target)));773 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target))));
774 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);774 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);
775 },775 },
776776
src/link/MachO/synthetic.zig+5-5
...@@ -267,7 +267,7 @@ pub const StubsSection = struct {...@@ -267,7 +267,7 @@ pub const StubsSection = struct {
267 },267 },
268 .aarch64 => {268 .aarch64 => {
269 // TODO relax if possible269 // TODO relax if possible
270 const pages = try aarch64.calcNumberOfPages(source, target);270 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
271 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);271 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
272 const off = try math.divExact(u12, @truncate(target), 8);272 const off = try math.divExact(u12, @truncate(target), 8);
273 try writer.writeInt(273 try writer.writeInt(
...@@ -411,7 +411,7 @@ pub const StubsHelperSection = struct {...@@ -411,7 +411,7 @@ pub const StubsHelperSection = struct {
411 .aarch64 => {411 .aarch64 => {
412 {412 {
413 // TODO relax if possible413 // TODO relax if possible
414 const pages = try aarch64.calcNumberOfPages(sect.addr, dyld_private_addr);414 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
415 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);415 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
416 const off: u12 = @truncate(dyld_private_addr);416 const off: u12 = @truncate(dyld_private_addr);
417 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);417 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
...@@ -424,7 +424,7 @@ pub const StubsHelperSection = struct {...@@ -424,7 +424,7 @@ pub const StubsHelperSection = struct {
424 ).toU32(), .little);424 ).toU32(), .little);
425 {425 {
426 // TODO relax if possible426 // TODO relax if possible
427 const pages = try aarch64.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr);427 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
428 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);428 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
429 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);429 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
430 try writer.writeInt(u32, aarch64.Instruction.ldr(430 try writer.writeInt(u32, aarch64.Instruction.ldr(
...@@ -679,7 +679,7 @@ pub const ObjcStubsSection = struct {...@@ -679,7 +679,7 @@ pub const ObjcStubsSection = struct {
679 {679 {
680 const target = sym.getObjcSelrefsAddress(macho_file);680 const target = sym.getObjcSelrefsAddress(macho_file);
681 const source = addr;681 const source = addr;
682 const pages = try aarch64.calcNumberOfPages(source, target);682 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
683 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);683 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
684 const off = try math.divExact(u12, @truncate(target), 8);684 const off = try math.divExact(u12, @truncate(target), 8);
685 try writer.writeInt(685 try writer.writeInt(
...@@ -692,7 +692,7 @@ pub const ObjcStubsSection = struct {...@@ -692,7 +692,7 @@ pub const ObjcStubsSection = struct {
692 const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);692 const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);
693 const target = target_sym.getGotAddress(macho_file);693 const target = target_sym.getGotAddress(macho_file);
694 const source = addr + 2 * @sizeOf(u32);694 const source = addr + 2 * @sizeOf(u32);
695 const pages = try aarch64.calcNumberOfPages(source, target);695 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
696 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);696 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
697 const off = try math.divExact(u12, @truncate(target), 8);697 const off = try math.divExact(u12, @truncate(target), 8);
698 try writer.writeInt(698 try writer.writeInt(
src/link/MachO/thunks.zig+1-1
...@@ -99,7 +99,7 @@ pub const Thunk = struct {...@@ -99,7 +99,7 @@ pub const Thunk = struct {
99 const sym = macho_file.getSymbol(sym_index);99 const sym = macho_file.getSymbol(sym_index);
100 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;100 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
101 const taddr = sym.getAddress(.{}, macho_file);101 const taddr = sym.getAddress(.{}, macho_file);
102 const pages = try aarch64.calcNumberOfPages(saddr, taddr);102 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
103 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);103 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
104 const off: u12 = @truncate(taddr);104 const off: u12 = @truncate(taddr);
105 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);105 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
src/link/aarch64.zig+1-1
...@@ -25,7 +25,7 @@ pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {...@@ -25,7 +25,7 @@ pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {
25 mem.writeInt(u32, code, inst.toU32(), .little);25 mem.writeInt(u32, code, inst.toU32(), .little);
26}26}
2727
28pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {28pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 {
29 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;29 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
30 const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;30 const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
31 const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;31 const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
test/link/elf.zig+182
...@@ -61,6 +61,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -61,6 +61,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
61 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));61 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));
62 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));62 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));
63 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));63 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));
64 elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));
64 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));65 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));
65 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));66 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));
66 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));67 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));
...@@ -72,6 +73,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -72,6 +73,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
72 elf_step.dependOn(testLinkingC(b, .{ .target = musl_target }));73 elf_step.dependOn(testLinkingC(b, .{ .target = musl_target }));
73 elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target }));74 elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target }));
74 elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target }));75 elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target }));
76 elf_step.dependOn(testMergeStrings(b, .{ .target = musl_target }));
77 elf_step.dependOn(testMergeStrings2(b, .{ .target = musl_target }));
75 // https://github.com/ziglang/zig/issues/1745178 // https://github.com/ziglang/zig/issues/17451
76 // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target }));79 // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target }));
77 elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target }));80 elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target }));
...@@ -81,6 +84,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -81,6 +84,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
81 elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target }));84 elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target }));
82 // https://github.com/ziglang/zig/issues/1743085 // https://github.com/ziglang/zig/issues/17430
83 // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target }));86 // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target }));
87 elf_step.dependOn(testCommentString(b, .{ .target = gnu_target }));
84 elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target }));88 elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target }));
85 // https://github.com/ziglang/zig/issues/1743089 // https://github.com/ziglang/zig/issues/17430
86 // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target }));90 // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target }));
...@@ -152,6 +156,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -152,6 +156,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
152 elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl }));156 elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl }));
153157
154 // x86_64 self-hosted backend158 // x86_64 self-hosted backend
159 elf_step.dependOn(testCommentString(b, .{ .use_llvm = false, .target = default_target }));
160 elf_step.dependOn(testCommentStringStaticLib(b, .{ .use_llvm = false, .target = default_target }));
155 elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl }));161 elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl }));
156 elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl }));162 elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl }));
157 elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target }));163 elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target }));
...@@ -362,6 +368,36 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {...@@ -362,6 +368,36 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
362 return test_step;368 return test_step;
363}369}
364370
371fn 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
386fn 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
365fn testCommonSymbols(b: *Build, opts: Options) *Step {401fn testCommonSymbols(b: *Build, opts: Options) *Step {
366 const test_step = addTestStep(b, "common-symbols", opts);402 const test_step = addTestStep(b, "common-symbols", opts);
367403
...@@ -2267,6 +2303,125 @@ fn testLinkingZig(b: *Build, opts: Options) *Step {...@@ -2267,6 +2303,125 @@ fn testLinkingZig(b: *Build, opts: Options) *Step {
2267 return test_step;2303 return test_step;
2268}2304}
22692305
2306// Adapted from https://github.com/rui314/mold/blob/main/test/elf/mergeable-strings.sh
2307fn 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
2362fn 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
2270fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {2425fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
2271 const test_step = addTestStep(b, "no-eh-frame-hdr", opts);2426 const test_step = addTestStep(b, "no-eh-frame-hdr", opts);
22722427
...@@ -2528,6 +2683,33 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2528,6 +2683,33 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2528 return test_step;2683 return test_step;
2529}2684}
25302685
2686// Adapted from https://github.com/rui314/mold/blob/main/test/elf/relocatable-mergeable-sections.sh
2687fn 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
2531fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {2713fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
2532 const test_step = addTestStep(b, "relocatable-no-eh-frame", opts);2714 const test_step = addTestStep(b, "relocatable-no-eh-frame", opts);
25332715
test/link/link.zig-18
...@@ -1,21 +1,3 @@...@@ -1,21 +1,3 @@
1pub 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
19pub const BuildOptions = struct {1pub const BuildOptions = struct {
20 has_macos_sdk: bool,2 has_macos_sdk: bool,
21 has_ios_sdk: bool,3 has_ios_sdk: bool,