Commit 17b8e8ab29
Changed files (1)
src
link
src/link/Elf.zig
@@ -1560,7 +1560,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// Generate and emit non-incremental sections.
try self.initSections();
try self.initSpecialPhdrs();
- try self.sortSections();
+ try self.sortShdrs();
for (self.objects.items) |index| {
try self.file(index).?.object.addAtomsToOutputSections(self);
}
@@ -4146,38 +4146,28 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
index.* = backlinks[index.*];
}
}
+
+ {
+ var it = self.phdr_to_shdr_table.iterator();
+ while (it.next()) |entry| {
+ entry.value_ptr.* = backlinks[entry.value_ptr.*];
+ }
+ }
}
-fn sectionRank(self: *Elf, shndx: u16) u8 {
+fn shdrRank(self: *Elf, shndx: u16) u8 {
const shdr = self.shdrs.items[shndx];
const name = self.shstrtab.getAssumeExists(shdr.sh_name);
const flags = shdr.sh_flags;
- if (self.isZigSection(shndx)) {
- switch (shdr.sh_type) {
- elf.SHT_PROGBITS => {
- assert(flags & elf.SHF_ALLOC != 0);
- if (flags & elf.SHF_EXECINSTR != 0) {
- return 0x2;
- } else if (flags & elf.SHF_WRITE != 0) {
- return 0x3;
- } else {
- return 0x1;
- }
- },
- elf.SHT_NOBITS => return 0xf,
- else => unreachable,
- }
- }
-
switch (shdr.sh_type) {
- elf.SHT_NULL => return 0x0,
- elf.SHT_DYNSYM => return 0x12,
- elf.SHT_HASH => return 0x13,
- elf.SHT_GNU_HASH => return 0x13,
- elf.SHT_GNU_VERSYM => return 0x14,
- elf.SHT_GNU_VERDEF => return 0x14,
- elf.SHT_GNU_VERNEED => return 0x14,
+ elf.SHT_NULL => return 0,
+ elf.SHT_DYNSYM => return 2,
+ elf.SHT_HASH => return 3,
+ elf.SHT_GNU_HASH => return 3,
+ elf.SHT_GNU_VERSYM => return 4,
+ elf.SHT_GNU_VERDEF => return 4,
+ elf.SHT_GNU_VERNEED => return 4,
elf.SHT_PREINIT_ARRAY,
elf.SHT_INIT_ARRAY,
@@ -4186,7 +4176,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
elf.SHT_DYNAMIC => return 0xf3,
- elf.SHT_RELA => return 0x1f,
+ elf.SHT_RELA => return 0xf,
elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
if (flags & elf.SHF_EXECINSTR != 0) {
@@ -4194,7 +4184,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
} else if (flags & elf.SHF_WRITE != 0) {
return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
} else if (mem.eql(u8, name, ".interp")) {
- return 0x11;
+ return 1;
} else {
return 0xf0;
}
@@ -4208,17 +4198,17 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
elf.SHT_SYMTAB => return 0xfa,
- elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x14 else 0xfb,
+ elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb,
else => return 0xff,
}
}
-fn sortSections(self: *Elf) !void {
+fn sortShdrs(self: *Elf) !void {
const Entry = struct {
shndx: u16,
pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
- return elf_file.sectionRank(lhs.shndx) < elf_file.sectionRank(rhs.shndx);
+ return elf_file.shdrRank(lhs.shndx) < elf_file.shdrRank(rhs.shndx);
}
};
@@ -4328,6 +4318,20 @@ fn sortSections(self: *Elf) !void {
shdr.sh_info = self.plt_section_index.?;
}
+ {
+ var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa);
+ defer phdr_to_shdr_table.deinit(gpa);
+
+ self.phdr_to_shdr_table.clearRetainingCapacity();
+
+ var it = phdr_to_shdr_table.iterator();
+ while (it.next()) |entry| {
+ const shndx = entry.key_ptr.*;
+ const phndx = entry.value_ptr.*;
+ self.phdr_to_shdr_table.putAssumeCapacityNoClobber(backlinks[shndx], phndx);
+ }
+ }
+
if (self.zig_module_index) |index| {
const zig_module = self.file(index).?.zig_module;
for (zig_module.atoms.items) |atom_index| {
@@ -4484,15 +4488,19 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
/// Calculates how many segments (PT_LOAD progam headers) are required
/// to cover the set of sections.
+/// We permit a maximum of 3**2 number of segments.
fn calcNumberOfSegments(self: *Elf) usize {
- var count: usize = 0;
- var flags: u64 = 0;
+ var covers: [9]bool = [_]bool{false} ** 9;
for (self.shdrs.items, 0..) |shdr, shndx| {
if (shdr.sh_type == elf.SHT_NULL) continue;
if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
if (self.isZigSection(@intCast(shndx))) continue;
- if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1;
- flags = shdrToPhdrFlags(shdr.sh_flags);
+ const flags = shdrToPhdrFlags(shdr.sh_flags);
+ covers[flags - 1] = true;
+ }
+ var count: usize = 0;
+ for (covers) |cover| {
+ if (cover) count += 1;
}
return count;
}
@@ -4564,34 +4572,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
// virtual and file offsets. However, the simple one will do for one
// as we are more interested in quick turnaround and compatibility
// with `findFreeSpace` mechanics than anything else.
+ const Cover = std.ArrayList(u16);
const gpa = self.base.allocator;
- const nphdrs = self.calcNumberOfSegments();
- var covers = try gpa.alloc(struct { start: u16, len: u16 }, nphdrs);
- defer gpa.free(covers);
+ var covers: [9]Cover = undefined;
+ for (&covers) |*cover| {
+ cover.* = Cover.init(gpa);
+ }
+ defer for (&covers) |*cover| {
+ cover.deinit();
+ };
- var shndx = for (self.shdrs.items, 0..) |shdr, in| {
+ for (self.shdrs.items, 0..) |shdr, shndx| {
if (shdr.sh_type == elf.SHT_NULL) continue;
if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
- if (self.isZigSection(@intCast(in))) continue;
- break @as(u16, @intCast(in));
- } else @as(u16, @intCast(self.shdrs.items.len));
-
- for (covers) |*cover| {
- cover.* = .{ .start = shndx, .len = 0 };
- var flags = shdrToPhdrFlags(self.shdrs.items[shndx].sh_flags);
-
- while (shndx < self.shdrs.items.len) : (shndx += 1) {
- const shdr = self.shdrs.items[shndx];
- if (shdr.sh_flags & elf.SHF_ALLOC == 0) break;
- if (shdrToPhdrFlags(shdr.sh_flags) != flags) {
- cover.len = shndx - cover.start;
- break;
- }
- }
- }
-
- if (nphdrs > 0) {
- covers[nphdrs - 1].len = shndx - covers[nphdrs - 1].start;
+ if (self.isZigSection(@intCast(shndx))) continue;
+ const flags = shdrToPhdrFlags(shdr.sh_flags);
+ try covers[flags - 1].append(@intCast(shndx));
}
// Now we can proceed with allocating the sections in virtual memory.
@@ -4603,10 +4599,11 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
var addr = phdr_table.p_vaddr + phdr_table.p_memsz;
for (covers) |cover| {
- const slice = self.shdrs.items[cover.start..][0..cover.len];
+ if (cover.items.len == 0) continue;
var @"align": u64 = self.page_size;
- for (slice) |shdr| {
+ for (cover.items) |shndx| {
+ const shdr = self.shdrs.items[shndx];
if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue;
@"align" = @max(@"align", shdr.sh_addralign);
}
@@ -4616,8 +4613,9 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
var memsz: u64 = 0;
var filesz: u64 = 0;
var i: usize = 0;
- while (i < cover.len) : (i += 1) {
- const shdr = &slice[i];
+ while (i < cover.items.len) : (i += 1) {
+ const shndx = cover.items[i];
+ const shdr = &self.shdrs.items[shndx];
if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) {
// .tbss is a little special as it's used only by the loader meaning it doesn't
// 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 {
// .data 0x10
// ...
var tbss_addr = addr;
- while (i < cover.len and
- slice[i].sh_type == elf.SHT_NOBITS and
- slice[i].sh_flags & elf.SHF_TLS != 0) : (i += 1)
+ while (i < cover.items.len and
+ self.shdrs.items[cover.items[i]].sh_type == elf.SHT_NOBITS and
+ self.shdrs.items[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1)
{
- const tbss_shdr = &slice[i];
- tbss_addr = alignment.@"align"(cover.start + i, tbss_shdr.sh_addralign, tbss_addr);
+ const tbss_shndx = cover.items[i];
+ const tbss_shdr = &self.shdrs.items[tbss_shndx];
+ tbss_addr = alignment.@"align"(tbss_shndx, tbss_shdr.sh_addralign, tbss_addr);
tbss_shdr.sh_addr = tbss_addr;
tbss_addr += tbss_shdr.sh_size;
}
i -= 1;
continue;
}
- const next = alignment.@"align"(cover.start + i, shdr.sh_addralign, addr);
+ const next = alignment.@"align"(shndx, shdr.sh_addralign, addr);
const padding = next - addr;
addr = next;
shdr.sh_addr = addr;
@@ -4655,23 +4654,25 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
addr += shdr.sh_size;
}
+ const first = self.shdrs.items[cover.items[0]];
var off = self.findFreeSpace(filesz, @"align");
const phndx = try self.addPhdr(.{
.type = elf.PT_LOAD,
.offset = off,
- .addr = slice[0].sh_addr,
+ .addr = first.sh_addr,
.memsz = memsz,
.filesz = filesz,
.@"align" = @"align",
- .flags = shdrToPhdrFlags(slice[0].sh_flags),
+ .flags = shdrToPhdrFlags(first.sh_flags),
});
- for (slice, 0..) |*shdr, ii| {
+ for (cover.items) |shndx| {
+ const shdr = &self.shdrs.items[shndx];
if (shdr.sh_type == elf.SHT_NOBITS) continue;
- off = alignment.@"align"(cover.start + ii, shdr.sh_addralign, off);
+ off = alignment.@"align"(shndx, shdr.sh_addralign, off);
shdr.sh_offset = off;
off += shdr.sh_size;
- try self.phdr_to_shdr_table.putNoClobber(gpa, @intCast(ii + cover.start), phndx);
+ try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx);
}
addr += self.page_size;