authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-10 14:55:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:05+02:00
log5148e38751e5f9415e226a6bc7f8f8c0d104f818
tree07ca3a507df24c27b6abe623766f3792abd5abe6
parent59fcf16732b614c998088f1d4c8d59a46d460ed5

elf: create and allocate special PHDRs out of the loop


1 files changed, 93 insertions(+), 67 deletions(-)

src/link/Elf.zig+93-67
...@@ -30,15 +30,13 @@ output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom....@@ -30,15 +30,13 @@ output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.
30/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.30/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
31/// Same order as in the file.31/// Same order as in the file.
32phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},32phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
33/// The index into the program headers of the PT_PHDR program header33
34phdr_table_index: ?u16 = null,34/// Tracked loadable segments during incremental linking.
35/// The index into the program headers of the PT_LOAD program header containing the phdr35/// The index into the program headers of the PT_LOAD program header containing the phdr
36/// Most linkers would merge this with phdr_load_ro_index,36/// Most linkers would merge this with phdr_load_ro_index,
37/// but incremental linking means we can't ensure they are consecutive.37/// but incremental linking means we can't ensure they are consecutive.
38/// If this segment is not needed, it won't get emitted.38/// If this segment is not needed, it won't get emitted.
39phdr_table_load_index: ?u16 = null,39phdr_table_load_index: ?u16 = null,
40/// The index into the program headers of the PT_TLS program header.
41phdr_tls_index: ?u16 = null,
42/// The index into the program headers of a PT_LOAD program header with Read and Execute flags40/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
43phdr_load_re_zig_index: ?u16 = null,41phdr_load_re_zig_index: ?u16 = null,
44/// The index into the program headers of the global offset table.42/// The index into the program headers of the global offset table.
...@@ -51,6 +49,20 @@ phdr_load_rw_zig_index: ?u16 = null,...@@ -51,6 +49,20 @@ phdr_load_rw_zig_index: ?u16 = null,
51/// The index into the program headers of a PT_LOAD program header with zerofill data.49/// The index into the program headers of a PT_LOAD program header with zerofill data.
52phdr_load_zerofill_zig_index: ?u16 = null,50phdr_load_zerofill_zig_index: ?u16 = null,
5351
52/// Special program headers
53/// PT_PHDR
54phdr_table_index: ?u16 = null,
55/// PT_INTERP
56phdr_interp_index: ?u16 = null,
57/// PT_DYNAMIC
58phdr_dynamic_index: ?u16 = null,
59/// PT_GNU_EH_FRAME
60phdr_gnu_eh_frame_index: ?u16 = null,
61/// PT_GNU_STACK
62phdr_gnu_stack_index: ?u16 = null,
63/// PT_TLS
64phdr_tls_index: ?u16 = null,
65
54entry_index: ?Symbol.Index = null,66entry_index: ?Symbol.Index = null,
55page_size: u32,67page_size: u32,
56default_sym_version: elf.Elf64_Versym,68default_sym_version: elf.Elf64_Versym,
...@@ -1607,6 +1619,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1607,6 +1619,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
16071619
1608 // Generate and emit non-incremental sections.1620 // Generate and emit non-incremental sections.
1609 try self.initSections();1621 try self.initSections();
1622 try self.initSpecialPhdrs();
1610 try self.sortSections();1623 try self.sortSections();
1611 for (self.objects.items) |index| {1624 for (self.objects.items) |index| {
1612 try self.file(index).?.object.addAtomsToOutputSections(self);1625 try self.file(index).?.object.addAtomsToOutputSections(self);
...@@ -1619,6 +1632,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1619,6 +1632,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1619 try self.updateSectionSizes();1632 try self.updateSectionSizes();
16201633
1621 try self.allocateSections();1634 try self.allocateSections();
1635 self.allocateSpecialPhdrs();
1622 self.allocateAtoms();1636 self.allocateAtoms();
1623 self.allocateLinkerDefinedSymbols();1637 self.allocateLinkerDefinedSymbols();
16241638
...@@ -4025,6 +4039,35 @@ fn initSections(self: *Elf) !void {...@@ -4025,6 +4039,35 @@ fn initSections(self: *Elf) !void {
4025 }4039 }
4026}4040}
40274041
4042fn initSpecialPhdrs(self: *Elf) !void {
4043 if (self.interp_section_index != null) {
4044 self.phdr_interp_index = try self.addPhdr(.{
4045 .type = elf.PT_INTERP,
4046 .flags = elf.PF_R,
4047 .@"align" = 1,
4048 });
4049 }
4050 if (self.dynamic_section_index != null) {
4051 self.phdr_dynamic_index = try self.addPhdr(.{
4052 .type = elf.PT_DYNAMIC,
4053 .flags = elf.PF_R | elf.PF_W,
4054 });
4055 }
4056 if (self.eh_frame_hdr_section_index != null) {
4057 self.phdr_gnu_eh_frame_index = try self.addPhdr(.{
4058 .type = elf.PT_GNU_EH_FRAME,
4059 .flags = elf.PF_R,
4060 });
4061 }
4062 self.phdr_gnu_stack_index = try self.addPhdr(.{
4063 .type = elf.PT_GNU_STACK,
4064 .flags = elf.PF_W | elf.PF_R,
4065 .memsz = self.base.options.stack_size_override orelse 0,
4066 .@"align" = 1,
4067 });
4068 // self.phdr_table_dirty = true;
4069}
4070
4028/// We need to sort constructors/destuctors in the following sections:4071/// We need to sort constructors/destuctors in the following sections:
4029/// * .init_array4072/// * .init_array
4030/// * .fini_array4073/// * .fini_array
...@@ -4416,31 +4459,33 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4416,31 +4459,33 @@ fn updateSectionSizes(self: *Elf) !void {
4416 }4459 }
4417}4460}
44184461
4462/// The assumed layout of PHDRs in file is as follows:
4463/// PT_PHDR
4464/// PT_INTERP
4465/// PT_DYNAMIC
4466/// PT_GNU_EH_FRAME
4467/// PT_GNU_STACK
4468/// PT_LOAD...
4469/// PT_TLS
4419fn resetPhdrs(self: *Elf) !void {4470fn resetPhdrs(self: *Elf) !void {
4420 const gpa = self.base.allocator;4471 const gpa = self.base.allocator;
4421 const phdrs = try self.phdrs.toOwnedSlice(gpa);4472 const phdrs = try self.phdrs.toOwnedSlice(gpa);
4422 try self.phdrs.ensureUnusedCapacity(gpa, phdrs.len);4473 try self.phdrs.ensureUnusedCapacity(gpa, phdrs.len);
44234474
4424 if (self.phdr_table_index) |phndx| {4475 for (&[_]?u16{
4425 self.phdrs.appendAssumeCapacity(phdrs[phndx]);4476 self.phdr_table_index.?,
4477 self.phdr_interp_index,
4478 self.phdr_dynamic_index,
4479 self.phdr_gnu_eh_frame_index,
4480 self.phdr_gnu_stack_index,
4481 }) |maybe_index| {
4482 if (maybe_index) |index| {
4483 self.phdrs.appendAssumeCapacity(phdrs[index]);
4484 }
4426 }4485 }
4427}4486}
44284487
4429fn initPhdrs(self: *Elf) !void {4488fn initSegments(self: *Elf) !void {
4430 // Add INTERP phdr if required
4431 if (self.interp_section_index) |index| {
4432 const shdr = self.shdrs.items[index];
4433 _ = try self.addPhdr(.{
4434 .type = elf.PT_INTERP,
4435 .flags = elf.PF_R,
4436 .@"align" = 1,
4437 .offset = shdr.sh_offset,
4438 .addr = shdr.sh_addr,
4439 .filesz = shdr.sh_size,
4440 .memsz = shdr.sh_size,
4441 });
4442 }
4443
4444 // Add LOAD phdrs4489 // Add LOAD phdrs
4445 const slice = self.shdrs.items;4490 const slice = self.shdrs.items;
4446 {4491 {
...@@ -4503,51 +4548,6 @@ fn initPhdrs(self: *Elf) !void {...@@ -4503,51 +4548,6 @@ fn initPhdrs(self: *Elf) !void {
4503 }4548 }
4504 }4549 }
4505 }4550 }
4506
4507 // Add DYNAMIC phdr
4508 if (self.dynamic_section_index) |index| {
4509 const shdr = self.shdrs.items[index];
4510 _ = try self.addPhdr(.{
4511 .type = elf.PT_DYNAMIC,
4512 .flags = elf.PF_R | elf.PF_W,
4513 .@"align" = shdr.sh_addralign,
4514 .offset = shdr.sh_offset,
4515 .addr = shdr.sh_addr,
4516 .memsz = shdr.sh_size,
4517 .filesz = shdr.sh_size,
4518 });
4519 }
4520
4521 // Add PT_GNU_EH_FRAME phdr if required.
4522 if (self.eh_frame_hdr_section_index) |index| {
4523 const shdr = self.shdrs.items[index];
4524 _ = try self.addPhdr(.{
4525 .type = elf.PT_GNU_EH_FRAME,
4526 .flags = elf.PF_R,
4527 .@"align" = shdr.sh_addralign,
4528 .offset = shdr.sh_offset,
4529 .addr = shdr.sh_addr,
4530 .memsz = shdr.sh_size,
4531 .filesz = shdr.sh_size,
4532 });
4533 }
4534
4535 // Add PT_GNU_STACK phdr that controls some stack attributes that apparently may or may not
4536 // be respected by the OS.
4537 _ = try self.addPhdr(.{
4538 .type = elf.PT_GNU_STACK,
4539 .flags = elf.PF_W | elf.PF_R,
4540 .memsz = self.base.options.stack_size_override orelse 0,
4541 .@"align" = 1,
4542 });
4543
4544 // Backpatch size of the PHDR phdr
4545 {
4546 const phdr = &self.phdrs.items[self.phdr_table_index.?];
4547 const size = @sizeOf(elf.Elf64_Phdr) * self.phdrs.items.len;
4548 phdr.p_filesz = size;
4549 phdr.p_memsz = size;
4550 }
4551}4551}
45524552
4553fn addShdrToPhdr(self: *Elf, phdr_index: u16, shdr: *const elf.Elf64_Shdr) !void {4553fn addShdrToPhdr(self: *Elf, phdr_index: u16, shdr: *const elf.Elf64_Shdr) !void {
...@@ -4716,11 +4716,37 @@ fn allocateSections(self: *Elf) !void {...@@ -4716,11 +4716,37 @@ fn allocateSections(self: *Elf) !void {
4716 self.allocateSectionsInMemory(base_offset);4716 self.allocateSectionsInMemory(base_offset);
4717 self.allocateSectionsInFile(base_offset);4717 self.allocateSectionsInFile(base_offset);
4718 try self.resetPhdrs();4718 try self.resetPhdrs();
4719 try self.initPhdrs();4719 try self.initSegments();
4720 if (nphdrs == self.phdrs.items.len) break;4720 if (nphdrs == self.phdrs.items.len) break;
4721 }4721 }
4722}4722}
47234723
4724fn allocateSpecialPhdrs(self: *Elf) void {
4725 for (&[_]struct { ?u16, ?u16 }{
4726 .{ self.phdr_interp_index, self.interp_section_index },
4727 .{ self.phdr_dynamic_index, self.dynamic_section_index },
4728 .{ self.phdr_gnu_eh_frame_index, self.eh_frame_hdr_section_index },
4729 }) |pair| {
4730 if (pair[0]) |index| {
4731 const shdr = self.shdrs.items[pair[1].?];
4732 const phdr = &self.phdrs.items[index];
4733 phdr.p_align = shdr.sh_addralign;
4734 phdr.p_offset = shdr.sh_offset;
4735 phdr.p_vaddr = shdr.sh_addr;
4736 phdr.p_filesz = shdr.sh_size;
4737 phdr.p_memsz = shdr.sh_size;
4738 }
4739 }
4740
4741 {
4742 // Backpatch size of the PHDR phdr
4743 const phdr = &self.phdrs.items[self.phdr_table_index.?];
4744 const size = @sizeOf(elf.Elf64_Phdr) * self.phdrs.items.len;
4745 phdr.p_filesz = size;
4746 phdr.p_memsz = size;
4747 }
4748}
4749
4724fn allocateAtoms(self: *Elf) void {4750fn allocateAtoms(self: *Elf) void {
4725 for (self.objects.items) |index| {4751 for (self.objects.items) |index| {
4726 self.file(index).?.object.allocateAtoms(self);4752 self.file(index).?.object.allocateAtoms(self);