authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-11 12:03:27+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:05+02:00
log8be71906d914563ea3e3e154ab948b4d78a1dcd3
tree47fc3995a3808b57749cb7d34cc1bde08806ddb4
parentbcce035636f14de6b2f39edea094d6eab3a321c9

elf: split allocating sections/segments into alloc and non-alloc


1 files changed, 123 insertions(+), 78 deletions(-)

src/link/Elf.zig+123-78
......@@ -60,6 +60,7 @@ phdr_gnu_eh_frame_index: ?u16 = null,
6060/// PT_GNU_STACK
6161phdr_gnu_stack_index: ?u16 = null,
6262/// PT_TLS
63/// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
6364phdr_tls_index: ?u16 = null,
6465
6566entry_index: ?Symbol.Index = null,
......@@ -1588,7 +1589,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15881589 try self.setVersionSymtab();
15891590 try self.updateSectionSizes();
15901591
1591 try self.allocateSections();
1592 try self.initAndAllocateSegments();
1593 self.allocateNonAllocSections();
15921594 self.allocateSpecialPhdrs();
15931595 self.allocateAtoms();
15941596 self.allocateLinkerDefinedSymbols();
......@@ -3996,6 +3998,16 @@ fn initSpecialPhdrs(self: *Elf) !void {
39963998 .memsz = self.base.options.stack_size_override orelse 0,
39973999 .@"align" = 1,
39984000 });
4001
4002 const has_tls = for (self.shdrs.items) |shdr| {
4003 if (shdr.sh_flags & elf.SHF_TLS != 0) break true;
4004 } else false;
4005 if (has_tls) {
4006 self.phdr_tls_index = try self.addPhdr(.{
4007 .type = elf.PT_TLS,
4008 .flags = elf.PF_R,
4009 });
4010 }
39994011}
40004012
40014013/// We need to sort constructors/destuctors in the following sections:
......@@ -4402,6 +4414,7 @@ fn resetPhdrs(self: *Elf) !void {
44024414 const gpa = self.base.allocator;
44034415 const phdrs = try self.phdrs.toOwnedSlice(gpa);
44044416 try self.phdrs.ensureUnusedCapacity(gpa, phdrs.len);
4417 self.phdr_to_shdr_table.clearRetainingCapacity(); // TODO move this into Section structure
44054418
44064419 for (&[_]?u16{
44074420 self.phdr_table_index,
......@@ -4410,6 +4423,7 @@ fn resetPhdrs(self: *Elf) !void {
44104423 self.phdr_dynamic_index,
44114424 self.phdr_gnu_eh_frame_index,
44124425 self.phdr_gnu_stack_index,
4426 self.phdr_tls_index,
44134427 }) |maybe_index| {
44144428 if (maybe_index) |index| {
44154429 self.phdrs.appendAssumeCapacity(phdrs[index]);
......@@ -4420,69 +4434,43 @@ fn resetPhdrs(self: *Elf) !void {
44204434fn initSegments(self: *Elf) !void {
44214435 // Add LOAD phdrs
44224436 const slice = self.shdrs.items;
4423 {
4424 var last_phdr: ?u16 = null;
4425 var shndx: usize = 0;
4426 while (shndx < slice.len) {
4427 const shdr = &slice[shndx];
4428 if (!shdrIsAlloc(shdr) or shdrIsTbss(shdr)) {
4429 shndx += 1;
4430 continue;
4431 }
4432 last_phdr = try self.addPhdr(.{
4433 .type = elf.PT_LOAD,
4434 .flags = shdrToPhdrFlags(shdr.sh_flags),
4435 .@"align" = @max(self.page_size, shdr.sh_addralign),
4436 .offset = if (last_phdr == null) 0 else shdr.sh_offset,
4437 .addr = if (last_phdr == null) self.calcImageBase() else shdr.sh_addr,
4438 });
4439 const p_flags = self.phdrs.items[last_phdr.?].p_flags;
4440 try self.addShdrToPhdr(last_phdr.?, shdr);
4437 var last_phdr: ?u16 = null;
4438 var shndx: u16 = 0;
4439 while (shndx < slice.len) {
4440 const shdr = &slice[shndx];
4441 if (!shdrIsAlloc(shdr) or shdrIsTbss(shdr)) {
44414442 shndx += 1;
4442
4443 while (shndx < slice.len) : (shndx += 1) {
4444 const next = &slice[shndx];
4445 if (shdrIsTbss(next)) continue;
4446 if (p_flags == shdrToPhdrFlags(next.sh_flags)) {
4447 if (shdrIsBss(next) or next.sh_offset - shdr.sh_offset == next.sh_addr - shdr.sh_addr) {
4448 try self.addShdrToPhdr(last_phdr.?, next);
4449 continue;
4450 }
4451 }
4452 break;
4453 }
4443 continue;
44544444 }
4455 }
4456
4457 // Add TLS phdr
4458 {
4459 var shndx: usize = 0;
4460 outer: while (shndx < slice.len) {
4461 const shdr = &slice[shndx];
4462 if (!shdrIsTls(shdr)) {
4463 shndx += 1;
4464 continue;
4465 }
4466 self.phdr_tls_index = try self.addPhdr(.{
4467 .type = elf.PT_TLS,
4468 .flags = elf.PF_R,
4469 .@"align" = shdr.sh_addralign,
4470 .offset = shdr.sh_offset,
4471 .addr = shdr.sh_addr,
4472 });
4473 try self.addShdrToPhdr(self.phdr_tls_index.?, shdr);
4474 shndx += 1;
4475
4476 while (shndx < slice.len) : (shndx += 1) {
4477 const next = &slice[shndx];
4478 if (!shdrIsTls(next)) continue :outer;
4479 try self.addShdrToPhdr(self.phdr_tls_index.?, next);
4445 last_phdr = try self.addPhdr(.{
4446 .type = elf.PT_LOAD,
4447 .flags = shdrToPhdrFlags(shdr.sh_flags),
4448 .@"align" = @max(self.page_size, shdr.sh_addralign),
4449 .offset = if (last_phdr == null) 0 else shdr.sh_offset,
4450 .addr = if (last_phdr == null) self.calcImageBase() else shdr.sh_addr,
4451 });
4452 const p_flags = self.phdrs.items[last_phdr.?].p_flags;
4453 self.addShdrToPhdr(shndx, last_phdr.?);
4454 try self.phdr_to_shdr_table.putNoClobber(self.base.allocator, shndx, last_phdr.?);
4455 shndx += 1;
4456
4457 while (shndx < slice.len) : (shndx += 1) {
4458 const next = &slice[shndx];
4459 if (shdrIsTbss(next)) continue;
4460 if (p_flags == shdrToPhdrFlags(next.sh_flags)) {
4461 if (shdrIsBss(next) or next.sh_offset - shdr.sh_offset == next.sh_addr - shdr.sh_addr) {
4462 self.addShdrToPhdr(shndx, last_phdr.?);
4463 try self.phdr_to_shdr_table.putNoClobber(self.base.allocator, shndx, last_phdr.?);
4464 continue;
4465 }
44804466 }
4467 break;
44814468 }
44824469 }
44834470}
44844471
4485fn addShdrToPhdr(self: *Elf, phdr_index: u16, shdr: *const elf.Elf64_Shdr) !void {
4472fn addShdrToPhdr(self: *Elf, shdr_index: u16, phdr_index: u16) void {
4473 const shdr = self.shdrs.items[shdr_index];
44864474 const phdr = &self.phdrs.items[phdr_index];
44874475 phdr.p_align = @max(phdr.p_align, shdr.sh_addralign);
44884476 if (shdr.sh_type != elf.SHT_NOBITS) {
......@@ -4520,7 +4508,7 @@ pub inline fn shdrIsTls(shdr: *const elf.Elf64_Shdr) bool {
45204508 return shdr.sh_flags & elf.SHF_TLS != 0;
45214509}
45224510
4523fn allocateSectionsInMemory(self: *Elf, base_offset: u64) void {
4511fn allocateAllocSectionsInMemory(self: *Elf, base_addr: u64) void {
45244512 // We use this struct to track maximum alignment of all TLS sections.
45254513 // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,
45264514 // in-file offsets have to be aligned against the start of TLS program header.
......@@ -4549,7 +4537,7 @@ fn allocateSectionsInMemory(self: *Elf, base_offset: u64) void {
45494537 alignment.tls_start_align = @max(alignment.tls_start_align, shdr.sh_addralign);
45504538 }
45514539
4552 var addr = self.calcImageBase() + base_offset;
4540 var addr = base_addr;
45534541 var i: usize = 0;
45544542 while (i < self.shdrs.items.len) : (i += 1) {
45554543 const shdr = &self.shdrs.items[i];
......@@ -4592,25 +4580,16 @@ fn allocateSectionsInMemory(self: *Elf, base_offset: u64) void {
45924580 }
45934581}
45944582
4595fn allocateSectionsInFile(self: *Elf, base_offset: u64) void {
4583fn allocateAllocSectionsInFile(self: *Elf, base_offset: u64) void {
45964584 var offset = base_offset;
45974585 var i: usize = 0;
45984586 while (i < self.shdrs.items.len) {
45994587 const first = &self.shdrs.items[i];
4600 defer if (!shdrIsAlloc(first) or shdrIsZerofill(first)) {
4588 if (shdrIsZerofill(first) or first.sh_type == elf.SHT_NULL) {
46014589 i += 1;
4602 };
4603
4604 if (first.sh_type == elf.SHT_NULL) continue;
4605
4606 // Non-alloc sections don't need congruency with their allocated virtual memory addresses
4607 if (!shdrIsAlloc(first)) {
4608 first.sh_offset = mem.alignForward(u64, offset, first.sh_addralign);
4609 offset = first.sh_offset + first.sh_size;
46104590 continue;
46114591 }
4612 // Skip any zerofill section
4613 if (shdrIsZerofill(first)) continue;
4592 if (!shdrIsAlloc(first)) break;
46144593
46154594 // Set the offset to a value that is congruent with the section's allocated virtual memory address
46164595 if (first.sh_addralign > self.page_size) {
......@@ -4637,11 +4616,26 @@ fn allocateSectionsInFile(self: *Elf, base_offset: u64) void {
46374616 offset = prev.sh_offset + prev.sh_size;
46384617
46394618 // Skip any zerofill section
4640 while (i < self.shdrs.items.len and shdrIsAlloc(&self.shdrs.items[i]) and shdrIsZerofill(&self.shdrs.items[i])) : (i += 1) {}
4619 while (i < self.shdrs.items.len and
4620 shdrIsAlloc(&self.shdrs.items[i]) and
4621 shdrIsZerofill(&self.shdrs.items[i])) : (i += 1)
4622 {}
4623 }
4624}
4625
4626fn allocateNonAllocSectionsInFile(self: *Elf, base_offset: u64) void {
4627 var offset = base_offset;
4628 var i: usize = 0;
4629 while (i < self.shdrs.items.len) : (i += 1) {
4630 const first = &self.shdrs.items[i];
4631 if (shdrIsAlloc(first) or first.sh_type == elf.SHT_NULL) continue;
4632 // Non-alloc sections don't need congruency with their allocated virtual memory addresses
4633 first.sh_offset = mem.alignForward(u64, offset, first.sh_addralign);
4634 offset = first.sh_offset + first.sh_size;
46414635 }
46424636}
46434637
4644fn allocateSections(self: *Elf) !void {
4638fn initAndAllocateSegments(self: *Elf) !void {
46454639 const ehsize: u64 = switch (self.ptr_width) {
46464640 .p32 => @sizeOf(elf.Elf32_Ehdr),
46474641 .p64 => @sizeOf(elf.Elf64_Ehdr),
......@@ -4650,17 +4644,29 @@ fn allocateSections(self: *Elf) !void {
46504644 .p32 => @sizeOf(elf.Elf32_Phdr),
46514645 .p64 => @sizeOf(elf.Elf64_Phdr),
46524646 };
4647 const image_base = self.calcImageBase();
46534648 while (true) {
46544649 const nphdrs = self.phdrs.items.len;
4655 const base_offset: u64 = ehsize + nphdrs * phsize;
4656 self.allocateSectionsInMemory(base_offset);
4657 self.allocateSectionsInFile(base_offset);
4650 const off = ehsize + nphdrs * phsize;
4651 const addr = image_base + off;
4652 self.allocateAllocSectionsInMemory(addr);
4653 self.allocateAllocSectionsInFile(off);
46584654 try self.resetPhdrs();
46594655 try self.initSegments();
46604656 if (nphdrs == self.phdrs.items.len) break;
46614657 }
46624658}
46634659
4660fn allocateNonAllocSections(self: *Elf) void {
4661 var off: u64 = 0;
4662 for (self.shdrs.items) |shdr| {
4663 if (shdr.sh_type == elf.SHT_NULL) continue;
4664 if (shdr.sh_flags & elf.SHF_ALLOC == 0) break;
4665 off = @max(off, shdr.sh_offset + shdr.sh_size);
4666 }
4667 self.allocateNonAllocSectionsInFile(off);
4668}
4669
46644670fn allocateSpecialPhdrs(self: *Elf) void {
46654671 for (&[_]struct { ?u16, ?u16 }{
46664672 .{ self.phdr_interp_index, self.interp_section_index },
......@@ -4677,6 +4683,32 @@ fn allocateSpecialPhdrs(self: *Elf) void {
46774683 phdr.p_memsz = shdr.sh_size;
46784684 }
46794685 }
4686
4687 // Allocate TLS phdr
4688 if (self.phdr_tls_index) |index| {
4689 const slice = self.shdrs.items;
4690 const phdr = &self.phdrs.items[index];
4691 var shndx: u16 = 0;
4692 outer: while (shndx < slice.len) {
4693 const shdr = slice[shndx];
4694 if (shdr.sh_flags & elf.SHF_TLS == 0) {
4695 shndx += 1;
4696 continue;
4697 }
4698 phdr.p_offset = shdr.sh_offset;
4699 phdr.p_vaddr = shdr.sh_addr;
4700 phdr.p_paddr = shdr.sh_addr;
4701 phdr.p_align = shdr.sh_addralign;
4702 self.addShdrToPhdr(shndx, index);
4703 shndx += 1;
4704
4705 while (shndx < slice.len) : (shndx += 1) {
4706 const next = slice[shndx];
4707 if (next.sh_flags & elf.SHF_TLS == 0) continue :outer;
4708 self.addShdrToPhdr(shndx, index);
4709 }
4710 }
4711 }
46804712}
46814713
46824714fn allocateAtoms(self: *Elf) void {
......@@ -5807,8 +5839,21 @@ fn formatPhdrs(
58075839 if (exec) flags[0] = 'X';
58085840 if (write) flags[1] = 'W';
58095841 if (read) flags[2] = 'R';
5810 try writer.print("phdr({d}) : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{
5811 i, flags, phdr.p_offset, phdr.p_vaddr, phdr.p_align, phdr.p_filesz, phdr.p_memsz,
5842 const p_type = switch (phdr.p_type) {
5843 elf.PT_LOAD => "LOAD",
5844 elf.PT_TLS => "TLS",
5845 elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME",
5846 elf.PT_GNU_STACK => "GNU_STACK",
5847 elf.PT_DYNAMIC => "DYNAMIC",
5848 elf.PT_INTERP => "INTERP",
5849 elf.PT_NULL => "NULL",
5850 elf.PT_PHDR => "PHDR",
5851 elf.PT_NOTE => "NOTE",
5852 else => "UNKNOWN",
5853 };
5854 try writer.print("phdr({d}) : {s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{
5855 i, p_type, flags, phdr.p_offset, phdr.p_vaddr,
5856 phdr.p_align, phdr.p_filesz, phdr.p_memsz,
58125857 });
58135858 }
58145859}