| ... | ... | @@ -1243,7 +1243,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1243 | 1243 | |
| 1244 | 1244 | // Generate and emit non-incremental sections. |
| 1245 | 1245 | try self.initSections(); |
| 1246 | | try self.initSyntheticSections(); |
| 1246 | try self.sortSections(); |
| 1247 | 1247 | |
| 1248 | 1248 | // Dump the state for easy debugging. |
| 1249 | 1249 | // State can be dumped via `--debug-log link_state`. |
| ... | ... | @@ -3430,6 +3430,11 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3430 | 3430 | } |
| 3431 | 3431 | |
| 3432 | 3432 | fn initSections(self: *Elf) !void { |
| 3433 | const small_ptr = switch (self.ptr_width) { |
| 3434 | .p32 => true, |
| 3435 | .p64 => false, |
| 3436 | }; |
| 3437 | |
| 3433 | 3438 | for (self.objects.items) |index| { |
| 3434 | 3439 | const object = self.file(index).?.object; |
| 3435 | 3440 | for (object.atoms.items) |atom_index| { |
| ... | ... | @@ -3439,13 +3444,6 @@ fn initSections(self: *Elf) !void { |
| 3439 | 3444 | atom_ptr.output_section_index = try object.getOutputSectionIndex(self, shdr); |
| 3440 | 3445 | } |
| 3441 | 3446 | } |
| 3442 | | } |
| 3443 | | |
| 3444 | | fn initSyntheticSections(self: *Elf) !void { |
| 3445 | | const small_ptr = switch (self.ptr_width) { |
| 3446 | | .p32 => true, |
| 3447 | | .p64 => false, |
| 3448 | | }; |
| 3449 | 3447 | |
| 3450 | 3448 | if (self.got.entries.items.len > 0 and self.got_section_index == null) { |
| 3451 | 3449 | self.got_section_index = try self.addSection(.{ |
| ... | ... | @@ -3482,6 +3480,113 @@ fn initSyntheticSections(self: *Elf) !void { |
| 3482 | 3480 | } |
| 3483 | 3481 | } |
| 3484 | 3482 | |
| 3483 | fn sectionRank(self: *Elf, shdr: elf.Elf64_Shdr) u8 { |
| 3484 | const name = self.shstrtab.getAssumeExists(shdr.sh_name); |
| 3485 | const flags = shdr.sh_flags; |
| 3486 | switch (shdr.sh_type) { |
| 3487 | elf.SHT_NULL => return 0, |
| 3488 | elf.SHT_DYNSYM => return 2, |
| 3489 | elf.SHT_HASH => return 3, |
| 3490 | elf.SHT_GNU_HASH => return 3, |
| 3491 | elf.SHT_GNU_VERSYM => return 4, |
| 3492 | elf.SHT_GNU_VERDEF => return 4, |
| 3493 | elf.SHT_GNU_VERNEED => return 4, |
| 3494 | |
| 3495 | elf.SHT_PREINIT_ARRAY, |
| 3496 | elf.SHT_INIT_ARRAY, |
| 3497 | elf.SHT_FINI_ARRAY, |
| 3498 | => return 0xf2, |
| 3499 | |
| 3500 | elf.SHT_DYNAMIC => return 0xf3, |
| 3501 | |
| 3502 | elf.SHT_RELA => return 0xf, |
| 3503 | |
| 3504 | elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { |
| 3505 | if (flags & elf.SHF_EXECINSTR != 0) { |
| 3506 | return 0xf1; |
| 3507 | } else if (flags & elf.SHF_WRITE != 0) { |
| 3508 | return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6; |
| 3509 | } else if (mem.eql(u8, name, ".interp")) { |
| 3510 | return 1; |
| 3511 | } else { |
| 3512 | return 0xf0; |
| 3513 | } |
| 3514 | } else { |
| 3515 | if (mem.startsWith(u8, name, ".debug")) { |
| 3516 | return 0xf8; |
| 3517 | } else { |
| 3518 | return 0xf9; |
| 3519 | } |
| 3520 | }, |
| 3521 | |
| 3522 | elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7, |
| 3523 | elf.SHT_SYMTAB => return 0xfa, |
| 3524 | elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 4 else 0xfb, |
| 3525 | else => return 0xff, |
| 3526 | } |
| 3527 | } |
| 3528 | |
| 3529 | fn sortSections(self: *Elf) !void { |
| 3530 | const Entry = struct { |
| 3531 | shndx: u16, |
| 3532 | |
| 3533 | pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { |
| 3534 | const lhs_shdr = elf_file.shdrs.items[lhs.shndx]; |
| 3535 | const rhs_shdr = elf_file.shdrs.items[rhs.shndx]; |
| 3536 | return elf_file.sectionRank(lhs_shdr) < elf_file.sectionRank(rhs_shdr); |
| 3537 | } |
| 3538 | }; |
| 3539 | |
| 3540 | const gpa = self.base.allocator; |
| 3541 | var entries = try std.ArrayList(Entry).initCapacity(gpa, self.shdrs.items.len); |
| 3542 | defer entries.deinit(); |
| 3543 | for (0..self.shdrs.items.len) |shndx| { |
| 3544 | entries.appendAssumeCapacity(.{ .shndx = @as(u16, @intCast(shndx)) }); |
| 3545 | } |
| 3546 | |
| 3547 | mem.sort(Entry, entries.items, self, Entry.lessThan); |
| 3548 | |
| 3549 | const backlinks = try gpa.alloc(u16, entries.items.len); |
| 3550 | defer gpa.free(backlinks); |
| 3551 | for (entries.items, 0..) |entry, i| { |
| 3552 | backlinks[entry.shndx] = @as(u16, @intCast(i)); |
| 3553 | } |
| 3554 | |
| 3555 | var slice = try self.shdrs.toOwnedSlice(gpa); |
| 3556 | defer gpa.free(slice); |
| 3557 | |
| 3558 | try self.shdrs.ensureTotalCapacityPrecise(gpa, slice.len); |
| 3559 | for (entries.items) |sorted| { |
| 3560 | self.shdrs.appendAssumeCapacity(slice[sorted.shndx]); |
| 3561 | } |
| 3562 | |
| 3563 | for (self.objects.items) |index| { |
| 3564 | for (self.file(index).?.object.atoms.items) |atom_index| { |
| 3565 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 3566 | if (!atom_ptr.flags.alive) continue; |
| 3567 | atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index]; |
| 3568 | } |
| 3569 | } |
| 3570 | |
| 3571 | for (&[_]*?u16{ |
| 3572 | &self.eh_frame_section_index, |
| 3573 | &self.eh_frame_hdr_section_index, |
| 3574 | &self.got_section_index, |
| 3575 | &self.symtab_section_index, |
| 3576 | &self.strtab_section_index, |
| 3577 | &self.shstrtab_section_index, |
| 3578 | }) |maybe_index| { |
| 3579 | if (maybe_index.*) |*index| { |
| 3580 | index.* = backlinks[index.*]; |
| 3581 | } |
| 3582 | } |
| 3583 | |
| 3584 | if (self.symtab_section_index) |index| { |
| 3585 | const shdr = &self.shdrs.items[index]; |
| 3586 | shdr.sh_link = self.strtab_section_index.?; |
| 3587 | } |
| 3588 | } |
| 3589 | |
| 3485 | 3590 | fn updateSyntheticSectionSizes(self: *Elf) !void { |
| 3486 | 3591 | if (self.got_section_index) |index| { |
| 3487 | 3592 | if (self.got.dirty) { |