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