| ... | ... | @@ -1560,7 +1560,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1560 | 1560 | // Generate and emit non-incremental sections. |
| 1561 | 1561 | try self.initSections(); |
| 1562 | 1562 | try self.initSpecialPhdrs(); |
| 1563 | | try self.sortSections(); |
| 1563 | try self.sortShdrs(); |
| 1564 | 1564 | for (self.objects.items) |index| { |
| 1565 | 1565 | try self.file(index).?.object.addAtomsToOutputSections(self); |
| 1566 | 1566 | } |
| ... | ... | @@ -4146,38 +4146,28 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { |
| 4146 | 4146 | index.* = backlinks[index.*]; |
| 4147 | 4147 | } |
| 4148 | 4148 | } |
| 4149 | |
| 4150 | { |
| 4151 | var it = self.phdr_to_shdr_table.iterator(); |
| 4152 | while (it.next()) |entry| { |
| 4153 | entry.value_ptr.* = backlinks[entry.value_ptr.*]; |
| 4154 | } |
| 4155 | } |
| 4149 | 4156 | } |
| 4150 | 4157 | |
| 4151 | | fn sectionRank(self: *Elf, shndx: u16) u8 { |
| 4158 | fn shdrRank(self: *Elf, shndx: u16) u8 { |
| 4152 | 4159 | const shdr = self.shdrs.items[shndx]; |
| 4153 | 4160 | const name = self.shstrtab.getAssumeExists(shdr.sh_name); |
| 4154 | 4161 | const flags = shdr.sh_flags; |
| 4155 | 4162 | |
| 4156 | | if (self.isZigSection(shndx)) { |
| 4157 | | switch (shdr.sh_type) { |
| 4158 | | elf.SHT_PROGBITS => { |
| 4159 | | assert(flags & elf.SHF_ALLOC != 0); |
| 4160 | | if (flags & elf.SHF_EXECINSTR != 0) { |
| 4161 | | return 0x2; |
| 4162 | | } else if (flags & elf.SHF_WRITE != 0) { |
| 4163 | | return 0x3; |
| 4164 | | } else { |
| 4165 | | return 0x1; |
| 4166 | | } |
| 4167 | | }, |
| 4168 | | elf.SHT_NOBITS => return 0xf, |
| 4169 | | else => unreachable, |
| 4170 | | } |
| 4171 | | } |
| 4172 | | |
| 4173 | 4163 | switch (shdr.sh_type) { |
| 4174 | | elf.SHT_NULL => return 0x0, |
| 4175 | | elf.SHT_DYNSYM => return 0x12, |
| 4176 | | elf.SHT_HASH => return 0x13, |
| 4177 | | elf.SHT_GNU_HASH => return 0x13, |
| 4178 | | elf.SHT_GNU_VERSYM => return 0x14, |
| 4179 | | elf.SHT_GNU_VERDEF => return 0x14, |
| 4180 | | elf.SHT_GNU_VERNEED => return 0x14, |
| 4164 | elf.SHT_NULL => return 0, |
| 4165 | elf.SHT_DYNSYM => return 2, |
| 4166 | elf.SHT_HASH => return 3, |
| 4167 | elf.SHT_GNU_HASH => return 3, |
| 4168 | elf.SHT_GNU_VERSYM => return 4, |
| 4169 | elf.SHT_GNU_VERDEF => return 4, |
| 4170 | elf.SHT_GNU_VERNEED => return 4, |
| 4181 | 4171 | |
| 4182 | 4172 | elf.SHT_PREINIT_ARRAY, |
| 4183 | 4173 | elf.SHT_INIT_ARRAY, |
| ... | ... | @@ -4186,7 +4176,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 { |
| 4186 | 4176 | |
| 4187 | 4177 | elf.SHT_DYNAMIC => return 0xf3, |
| 4188 | 4178 | |
| 4189 | | elf.SHT_RELA => return 0x1f, |
| 4179 | elf.SHT_RELA => return 0xf, |
| 4190 | 4180 | |
| 4191 | 4181 | elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { |
| 4192 | 4182 | if (flags & elf.SHF_EXECINSTR != 0) { |
| ... | ... | @@ -4194,7 +4184,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 { |
| 4194 | 4184 | } else if (flags & elf.SHF_WRITE != 0) { |
| 4195 | 4185 | return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6; |
| 4196 | 4186 | } else if (mem.eql(u8, name, ".interp")) { |
| 4197 | | return 0x11; |
| 4187 | return 1; |
| 4198 | 4188 | } else { |
| 4199 | 4189 | return 0xf0; |
| 4200 | 4190 | } |
| ... | ... | @@ -4208,17 +4198,17 @@ fn sectionRank(self: *Elf, shndx: u16) u8 { |
| 4208 | 4198 | |
| 4209 | 4199 | elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7, |
| 4210 | 4200 | elf.SHT_SYMTAB => return 0xfa, |
| 4211 | | elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x14 else 0xfb, |
| 4201 | elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb, |
| 4212 | 4202 | else => return 0xff, |
| 4213 | 4203 | } |
| 4214 | 4204 | } |
| 4215 | 4205 | |
| 4216 | | fn sortSections(self: *Elf) !void { |
| 4206 | fn sortShdrs(self: *Elf) !void { |
| 4217 | 4207 | const Entry = struct { |
| 4218 | 4208 | shndx: u16, |
| 4219 | 4209 | |
| 4220 | 4210 | pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { |
| 4221 | | return elf_file.sectionRank(lhs.shndx) < elf_file.sectionRank(rhs.shndx); |
| 4211 | return elf_file.shdrRank(lhs.shndx) < elf_file.shdrRank(rhs.shndx); |
| 4222 | 4212 | } |
| 4223 | 4213 | }; |
| 4224 | 4214 | |
| ... | ... | @@ -4328,6 +4318,20 @@ fn sortSections(self: *Elf) !void { |
| 4328 | 4318 | shdr.sh_info = self.plt_section_index.?; |
| 4329 | 4319 | } |
| 4330 | 4320 | |
| 4321 | { |
| 4322 | var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa); |
| 4323 | defer phdr_to_shdr_table.deinit(gpa); |
| 4324 | |
| 4325 | self.phdr_to_shdr_table.clearRetainingCapacity(); |
| 4326 | |
| 4327 | var it = phdr_to_shdr_table.iterator(); |
| 4328 | while (it.next()) |entry| { |
| 4329 | const shndx = entry.key_ptr.*; |
| 4330 | const phndx = entry.value_ptr.*; |
| 4331 | self.phdr_to_shdr_table.putAssumeCapacityNoClobber(backlinks[shndx], phndx); |
| 4332 | } |
| 4333 | } |
| 4334 | |
| 4331 | 4335 | if (self.zig_module_index) |index| { |
| 4332 | 4336 | const zig_module = self.file(index).?.zig_module; |
| 4333 | 4337 | for (zig_module.atoms.items) |atom_index| { |
| ... | ... | @@ -4484,15 +4488,19 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 { |
| 4484 | 4488 | |
| 4485 | 4489 | /// Calculates how many segments (PT_LOAD progam headers) are required |
| 4486 | 4490 | /// to cover the set of sections. |
| 4491 | /// We permit a maximum of 3**2 number of segments. |
| 4487 | 4492 | fn calcNumberOfSegments(self: *Elf) usize { |
| 4488 | | var count: usize = 0; |
| 4489 | | var flags: u64 = 0; |
| 4493 | var covers: [9]bool = [_]bool{false} ** 9; |
| 4490 | 4494 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 4491 | 4495 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4492 | 4496 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4493 | 4497 | if (self.isZigSection(@intCast(shndx))) continue; |
| 4494 | | if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1; |
| 4495 | | flags = shdrToPhdrFlags(shdr.sh_flags); |
| 4498 | const flags = shdrToPhdrFlags(shdr.sh_flags); |
| 4499 | covers[flags - 1] = true; |
| 4500 | } |
| 4501 | var count: usize = 0; |
| 4502 | for (covers) |cover| { |
| 4503 | if (cover) count += 1; |
| 4496 | 4504 | } |
| 4497 | 4505 | return count; |
| 4498 | 4506 | } |
| ... | ... | @@ -4564,34 +4572,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4564 | 4572 | // virtual and file offsets. However, the simple one will do for one |
| 4565 | 4573 | // as we are more interested in quick turnaround and compatibility |
| 4566 | 4574 | // with `findFreeSpace` mechanics than anything else. |
| 4575 | const Cover = std.ArrayList(u16); |
| 4567 | 4576 | const gpa = self.base.allocator; |
| 4568 | | const nphdrs = self.calcNumberOfSegments(); |
| 4569 | | var covers = try gpa.alloc(struct { start: u16, len: u16 }, nphdrs); |
| 4570 | | defer gpa.free(covers); |
| 4577 | var covers: [9]Cover = undefined; |
| 4578 | for (&covers) |*cover| { |
| 4579 | cover.* = Cover.init(gpa); |
| 4580 | } |
| 4581 | defer for (&covers) |*cover| { |
| 4582 | cover.deinit(); |
| 4583 | }; |
| 4571 | 4584 | |
| 4572 | | var shndx = for (self.shdrs.items, 0..) |shdr, in| { |
| 4585 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 4573 | 4586 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4574 | 4587 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4575 | | if (self.isZigSection(@intCast(in))) continue; |
| 4576 | | break @as(u16, @intCast(in)); |
| 4577 | | } else @as(u16, @intCast(self.shdrs.items.len)); |
| 4578 | | |
| 4579 | | for (covers) |*cover| { |
| 4580 | | cover.* = .{ .start = shndx, .len = 0 }; |
| 4581 | | var flags = shdrToPhdrFlags(self.shdrs.items[shndx].sh_flags); |
| 4582 | | |
| 4583 | | while (shndx < self.shdrs.items.len) : (shndx += 1) { |
| 4584 | | const shdr = self.shdrs.items[shndx]; |
| 4585 | | if (shdr.sh_flags & elf.SHF_ALLOC == 0) break; |
| 4586 | | if (shdrToPhdrFlags(shdr.sh_flags) != flags) { |
| 4587 | | cover.len = shndx - cover.start; |
| 4588 | | break; |
| 4589 | | } |
| 4590 | | } |
| 4591 | | } |
| 4592 | | |
| 4593 | | if (nphdrs > 0) { |
| 4594 | | covers[nphdrs - 1].len = shndx - covers[nphdrs - 1].start; |
| 4588 | if (self.isZigSection(@intCast(shndx))) continue; |
| 4589 | const flags = shdrToPhdrFlags(shdr.sh_flags); |
| 4590 | try covers[flags - 1].append(@intCast(shndx)); |
| 4595 | 4591 | } |
| 4596 | 4592 | |
| 4597 | 4593 | // Now we can proceed with allocating the sections in virtual memory. |
| ... | ... | @@ -4603,10 +4599,11 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4603 | 4599 | var addr = phdr_table.p_vaddr + phdr_table.p_memsz; |
| 4604 | 4600 | |
| 4605 | 4601 | for (covers) |cover| { |
| 4606 | | const slice = self.shdrs.items[cover.start..][0..cover.len]; |
| 4602 | if (cover.items.len == 0) continue; |
| 4607 | 4603 | |
| 4608 | 4604 | var @"align": u64 = self.page_size; |
| 4609 | | for (slice) |shdr| { |
| 4605 | for (cover.items) |shndx| { |
| 4606 | const shdr = self.shdrs.items[shndx]; |
| 4610 | 4607 | if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue; |
| 4611 | 4608 | @"align" = @max(@"align", shdr.sh_addralign); |
| 4612 | 4609 | } |
| ... | ... | @@ -4616,8 +4613,9 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4616 | 4613 | var memsz: u64 = 0; |
| 4617 | 4614 | var filesz: u64 = 0; |
| 4618 | 4615 | var i: usize = 0; |
| 4619 | | while (i < cover.len) : (i += 1) { |
| 4620 | | const shdr = &slice[i]; |
| 4616 | while (i < cover.items.len) : (i += 1) { |
| 4617 | const shndx = cover.items[i]; |
| 4618 | const shdr = &self.shdrs.items[shndx]; |
| 4621 | 4619 | if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) { |
| 4622 | 4620 | // .tbss is a little special as it's used only by the loader meaning it doesn't |
| 4623 | 4621 | // need to be actually mmap'ed at runtime. We still need to correctly increment |
| ... | ... | @@ -4632,19 +4630,20 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4632 | 4630 | // .data 0x10 |
| 4633 | 4631 | // ... |
| 4634 | 4632 | var tbss_addr = addr; |
| 4635 | | while (i < cover.len and |
| 4636 | | slice[i].sh_type == elf.SHT_NOBITS and |
| 4637 | | slice[i].sh_flags & elf.SHF_TLS != 0) : (i += 1) |
| 4633 | while (i < cover.items.len and |
| 4634 | self.shdrs.items[cover.items[i]].sh_type == elf.SHT_NOBITS and |
| 4635 | self.shdrs.items[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1) |
| 4638 | 4636 | { |
| 4639 | | const tbss_shdr = &slice[i]; |
| 4640 | | tbss_addr = alignment.@"align"(cover.start + i, tbss_shdr.sh_addralign, tbss_addr); |
| 4637 | const tbss_shndx = cover.items[i]; |
| 4638 | const tbss_shdr = &self.shdrs.items[tbss_shndx]; |
| 4639 | tbss_addr = alignment.@"align"(tbss_shndx, tbss_shdr.sh_addralign, tbss_addr); |
| 4641 | 4640 | tbss_shdr.sh_addr = tbss_addr; |
| 4642 | 4641 | tbss_addr += tbss_shdr.sh_size; |
| 4643 | 4642 | } |
| 4644 | 4643 | i -= 1; |
| 4645 | 4644 | continue; |
| 4646 | 4645 | } |
| 4647 | | const next = alignment.@"align"(cover.start + i, shdr.sh_addralign, addr); |
| 4646 | const next = alignment.@"align"(shndx, shdr.sh_addralign, addr); |
| 4648 | 4647 | const padding = next - addr; |
| 4649 | 4648 | addr = next; |
| 4650 | 4649 | shdr.sh_addr = addr; |
| ... | ... | @@ -4655,23 +4654,25 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4655 | 4654 | addr += shdr.sh_size; |
| 4656 | 4655 | } |
| 4657 | 4656 | |
| 4657 | const first = self.shdrs.items[cover.items[0]]; |
| 4658 | 4658 | var off = self.findFreeSpace(filesz, @"align"); |
| 4659 | 4659 | const phndx = try self.addPhdr(.{ |
| 4660 | 4660 | .type = elf.PT_LOAD, |
| 4661 | 4661 | .offset = off, |
| 4662 | | .addr = slice[0].sh_addr, |
| 4662 | .addr = first.sh_addr, |
| 4663 | 4663 | .memsz = memsz, |
| 4664 | 4664 | .filesz = filesz, |
| 4665 | 4665 | .@"align" = @"align", |
| 4666 | | .flags = shdrToPhdrFlags(slice[0].sh_flags), |
| 4666 | .flags = shdrToPhdrFlags(first.sh_flags), |
| 4667 | 4667 | }); |
| 4668 | 4668 | |
| 4669 | | for (slice, 0..) |*shdr, ii| { |
| 4669 | for (cover.items) |shndx| { |
| 4670 | const shdr = &self.shdrs.items[shndx]; |
| 4670 | 4671 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 4671 | | off = alignment.@"align"(cover.start + ii, shdr.sh_addralign, off); |
| 4672 | off = alignment.@"align"(shndx, shdr.sh_addralign, off); |
| 4672 | 4673 | shdr.sh_offset = off; |
| 4673 | 4674 | off += shdr.sh_size; |
| 4674 | | try self.phdr_to_shdr_table.putNoClobber(gpa, @intCast(ii + cover.start), phndx); |
| 4675 | try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx); |
| 4675 | 4676 | } |
| 4676 | 4677 | |
| 4677 | 4678 | addr += self.page_size; |