authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-03 13:55:20-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-03 14:17:43-04:00
log9fd460821f992c51b35a54ba93562af93ac478f6
treedc9aa40cfa05f1255b1539592cc8f3a826df228e
parentc0e9b849974cdbc93053919f54f0cf3830243572

elf: cleanup phdr tracking

Since one of the program header entries is now the program header table itself, we can avoid tracking it explicitly and just track it as yet another program segment.

1 files changed, 133 insertions(+), 162 deletions(-)

src/link/Elf.zig+133-162
...@@ -391,17 +391,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -391,17 +391,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
391391
392 const end = start + padToIdeal(size);392 const end = start + padToIdeal(size);
393393
394 if (self.phdr_table_index) |index| {
395 const off = self.program_headers.items[index].p_offset;
396 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
397 const tight_size = self.program_headers.items.len * phdr_size;
398 const increased_size = padToIdeal(tight_size);
399 const test_end = off + increased_size;
400 if (end > off and start < test_end) {
401 return test_end;
402 }
403 }
404
405 if (self.shdr_table_offset) |off| {394 if (self.shdr_table_offset) |off| {
406 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);395 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
407 const tight_size = self.sections.slice().len * shdr_size;396 const tight_size = self.sections.slice().len * shdr_size;
...@@ -433,10 +422,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {...@@ -433,10 +422,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
433 if (start == 0)422 if (start == 0)
434 return 0;423 return 0;
435 var min_pos: u64 = std.math.maxInt(u64);424 var min_pos: u64 = std.math.maxInt(u64);
436 if (self.phdr_table_index) |index| {
437 const off = self.program_headers.items[index].p_offset;
438 if (off > start and off < min_pos) min_pos = off;
439 }
440 if (self.shdr_table_offset) |off| {425 if (self.shdr_table_offset) |off| {
441 if (off > start and off < min_pos) min_pos = off;426 if (off > start and off < min_pos) min_pos = off;
442 }427 }
...@@ -469,151 +454,133 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -469,151 +454,133 @@ pub fn populateMissingMetadata(self: *Elf) !void {
469 };454 };
470 const ptr_size: u8 = self.ptrWidthBytes();455 const ptr_size: u8 = self.ptrWidthBytes();
471456
472 { // Program Headers457 if (self.phdr_table_index == null) {
473 var new_phdr_table_index: ?u16 = null;458 self.phdr_table_index = @intCast(u16, self.program_headers.items.len);
474 if (self.phdr_table_index == null) {459 const p_align: u16 = switch (self.ptr_width) {
475 new_phdr_table_index = @intCast(u16, self.program_headers.items.len);460 .p32 => @alignOf(elf.Elf32_Phdr),
476 const p_align: u16 = switch (self.ptr_width) {461 .p64 => @alignOf(elf.Elf64_Phdr),
477 .p32 => @alignOf(elf.Elf32_Phdr),462 };
478 .p64 => @alignOf(elf.Elf64_Phdr),463 try self.program_headers.append(gpa, .{
479 };464 .p_type = elf.PT_PHDR,
480 const off = self.findFreeSpace(1, p_align);465 .p_offset = 0,
481 try self.program_headers.append(gpa, .{466 .p_filesz = 0,
482 .p_type = elf.PT_PHDR,467 .p_vaddr = 0,
483 .p_offset = off,468 .p_paddr = 0,
484 .p_filesz = 1,469 .p_memsz = 0,
485 .p_vaddr = 0,470 .p_align = p_align,
486 .p_paddr = 0,471 .p_flags = elf.PF_R,
487 .p_memsz = 0,472 });
488 .p_align = p_align,473 self.phdr_table_dirty = true;
489 .p_flags = elf.PF_R,474 }
490 });475
491 self.phdr_table_dirty = true;476 if (self.phdr_table_load_index == null) {
492 }477 self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
493478 // TODO Same as for GOT
494 if (self.phdr_table_load_index == null) {479 const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
495 self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);480 const p_align = self.page_size;
496 // TODO Same as for GOT481 try self.program_headers.append(gpa, .{
497 const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;482 .p_type = elf.PT_LOAD,
498 const p_align = self.page_size;483 .p_offset = 0,
499 const off = self.findFreeSpace(1, p_align);484 .p_filesz = 0,
500 const file_size: u32 = 1;485 .p_vaddr = phdr_addr,
501 log.debug("found PT_LOAD free space 0x{x} to 0x{x}", .{ off, off + file_size });486 .p_paddr = phdr_addr,
502 try self.program_headers.append(gpa, .{487 .p_memsz = 0,
503 .p_type = elf.PT_LOAD,488 .p_align = p_align,
504 .p_offset = off,489 .p_flags = elf.PF_R,
505 .p_filesz = file_size,490 });
506 .p_vaddr = phdr_addr,491 self.phdr_table_dirty = true;
507 .p_paddr = phdr_addr,492 }
508 .p_memsz = file_size,493
509 .p_align = p_align,494 if (self.phdr_load_re_index == null) {
510 .p_flags = elf.PF_R,495 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
511 });496 const file_size = self.base.options.program_code_size_hint;
512 self.phdr_table_dirty = true;497 const p_align = self.page_size;
513 }498 const off = self.findFreeSpace(file_size, p_align);
514499 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
515 if (self.phdr_load_re_index == null) {500 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
516 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);501 try self.program_headers.append(gpa, .{
517 const file_size = self.base.options.program_code_size_hint;502 .p_type = elf.PT_LOAD,
518 const p_align = self.page_size;503 .p_offset = off,
519 const off = self.findFreeSpace(file_size, p_align);504 .p_filesz = file_size,
520 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });505 .p_vaddr = entry_addr,
521 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;506 .p_paddr = entry_addr,
522 try self.program_headers.append(gpa, .{507 .p_memsz = file_size,
523 .p_type = elf.PT_LOAD,508 .p_align = p_align,
524 .p_offset = off,509 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
525 .p_filesz = file_size,510 });
526 .p_vaddr = entry_addr,511 self.entry_addr = null;
527 .p_paddr = entry_addr,512 self.phdr_table_dirty = true;
528 .p_memsz = file_size,513 }
529 .p_align = p_align,514
530 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,515 if (self.phdr_got_index == null) {
531 });516 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
532 self.entry_addr = null;517 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
533 self.phdr_table_dirty = true;518 // We really only need ptr alignment but since we are using PROGBITS, linux requires
534 }519 // page align.
535520 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
536 if (self.phdr_got_index == null) {521 const off = self.findFreeSpace(file_size, p_align);
537 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);522 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
538 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;523 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
539 // We really only need ptr alignment but since we are using PROGBITS, linux requires524 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
540 // page align.525 // else in virtual memory.
541 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);526 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
542 const off = self.findFreeSpace(file_size, p_align);527 try self.program_headers.append(gpa, .{
543 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });528 .p_type = elf.PT_LOAD,
544 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.529 .p_offset = off,
545 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something530 .p_filesz = file_size,
546 // else in virtual memory.531 .p_vaddr = got_addr,
547 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;532 .p_paddr = got_addr,
548 try self.program_headers.append(gpa, .{533 .p_memsz = file_size,
549 .p_type = elf.PT_LOAD,534 .p_align = p_align,
550 .p_offset = off,535 .p_flags = elf.PF_R | elf.PF_W,
551 .p_filesz = file_size,536 });
552 .p_vaddr = got_addr,537 self.phdr_table_dirty = true;
553 .p_paddr = got_addr,538 }
554 .p_memsz = file_size,539
555 .p_align = p_align,540 if (self.phdr_load_ro_index == null) {
556 .p_flags = elf.PF_R | elf.PF_W,541 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
557 });542 // TODO Find a hint about how much data need to be in rodata ?
558 self.phdr_table_dirty = true;543 const file_size = 1024;
559 }544 // Same reason as for GOT
560545 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
561 if (self.phdr_load_ro_index == null) {546 const off = self.findFreeSpace(file_size, p_align);
562 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);547 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
563 // TODO Find a hint about how much data need to be in rodata ?548 // TODO Same as for GOT
564 const file_size = 1024;549 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
565 // Same reason as for GOT550 try self.program_headers.append(gpa, .{
566 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);551 .p_type = elf.PT_LOAD,
567 const off = self.findFreeSpace(file_size, p_align);552 .p_offset = off,
568 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });553 .p_filesz = file_size,
569 // TODO Same as for GOT554 .p_vaddr = rodata_addr,
570 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;555 .p_paddr = rodata_addr,
571 try self.program_headers.append(gpa, .{556 .p_memsz = file_size,
572 .p_type = elf.PT_LOAD,557 .p_align = p_align,
573 .p_offset = off,558 .p_flags = elf.PF_R | elf.PF_W,
574 .p_filesz = file_size,559 });
575 .p_vaddr = rodata_addr,560 self.phdr_table_dirty = true;
576 .p_paddr = rodata_addr,561 }
577 .p_memsz = file_size,562
578 .p_align = p_align,563 if (self.phdr_load_rw_index == null) {
579 .p_flags = elf.PF_R | elf.PF_W,564 self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
580 });565 // TODO Find a hint about how much data need to be in data ?
581 self.phdr_table_dirty = true;566 const file_size = 1024;
582 }567 // Same reason as for GOT
583568 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
584 if (self.phdr_load_rw_index == null) {569 const off = self.findFreeSpace(file_size, p_align);
585 self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);570 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
586 // TODO Find a hint about how much data need to be in data ?571 // TODO Same as for GOT
587 const file_size = 1024;572 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
588 // Same reason as for GOT573 try self.program_headers.append(gpa, .{
589 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);574 .p_type = elf.PT_LOAD,
590 const off = self.findFreeSpace(file_size, p_align);575 .p_offset = off,
591 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });576 .p_filesz = file_size,
592 // TODO Same as for GOT577 .p_vaddr = rwdata_addr,
593 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;578 .p_paddr = rwdata_addr,
594 try self.program_headers.append(gpa, .{579 .p_memsz = file_size,
595 .p_type = elf.PT_LOAD,580 .p_align = p_align,
596 .p_offset = off,581 .p_flags = elf.PF_R | elf.PF_W,
597 .p_filesz = file_size,582 });
598 .p_vaddr = rwdata_addr,583 self.phdr_table_dirty = true;
599 .p_paddr = rwdata_addr,
600 .p_memsz = file_size,
601 .p_align = p_align,
602 .p_flags = elf.PF_R | elf.PF_W,
603 });
604 self.phdr_table_dirty = true;
605 }
606
607 if (new_phdr_table_index) |index| {
608 const phsize: u64 = switch (self.ptr_width) {
609 .p32 => @sizeOf(elf.Elf32_Phdr),
610 .p64 => @sizeOf(elf.Elf64_Phdr),
611 };
612 const phdr_table = &self.program_headers.items[index];
613 phdr_table.p_offset = self.findFreeSpace(self.program_headers.items.len * phsize, @intCast(u32, phdr_table.p_align));
614 self.phdr_table_index = index;
615 self.phdr_table_dirty = true;
616 }
617 }584 }
618585
619 if (self.shstrtab_index == null) {586 if (self.shstrtab_index == null) {
...@@ -1186,8 +1153,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1186,8 +1153,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1186 const needed_size = self.program_headers.items.len * phsize;1153 const needed_size = self.program_headers.items.len * phsize;
11871154
1188 if (needed_size > allocated_size) {1155 if (needed_size > allocated_size) {
1189 self.phdr_table_index = null; // free the space1156 phdr_table.p_offset = 0; // free the space
1190 defer self.phdr_table_index = phdr_table_index;
1191 phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));1157 phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));
1192 }1158 }
11931159
...@@ -1227,6 +1193,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1227,6 +1193,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1227 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);1193 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
1228 },1194 },
1229 }1195 }
1196
1197 // We don't actually care if the phdr load section overlaps, only the phdr section matters.
1198 phdr_table_load.p_offset = 0;
1199 phdr_table_load.p_filesz = 0;
1200
1230 self.phdr_table_dirty = false;1201 self.phdr_table_dirty = false;
1231 }1202 }
12321203