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 {
391391
392392 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
405394 if (self.shdr_table_offset) |off| {
406395 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
407396 const tight_size = self.sections.slice().len * shdr_size;
......@@ -433,10 +422,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
433422 if (start == 0)
434423 return 0;
435424 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 }
440425 if (self.shdr_table_offset) |off| {
441426 if (off > start and off < min_pos) min_pos = off;
442427 }
......@@ -469,151 +454,133 @@ pub fn populateMissingMetadata(self: *Elf) !void {
469454 };
470455 const ptr_size: u8 = self.ptrWidthBytes();
471456
472 { // Program Headers
473 var new_phdr_table_index: ?u16 = null;
474 if (self.phdr_table_index == null) {
475 new_phdr_table_index = @intCast(u16, self.program_headers.items.len);
476 const p_align: u16 = switch (self.ptr_width) {
477 .p32 => @alignOf(elf.Elf32_Phdr),
478 .p64 => @alignOf(elf.Elf64_Phdr),
479 };
480 const off = self.findFreeSpace(1, p_align);
481 try self.program_headers.append(gpa, .{
482 .p_type = elf.PT_PHDR,
483 .p_offset = off,
484 .p_filesz = 1,
485 .p_vaddr = 0,
486 .p_paddr = 0,
487 .p_memsz = 0,
488 .p_align = p_align,
489 .p_flags = elf.PF_R,
490 });
491 self.phdr_table_dirty = true;
492 }
493
494 if (self.phdr_table_load_index == null) {
495 self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
496 // TODO Same as for GOT
497 const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
498 const p_align = self.page_size;
499 const off = self.findFreeSpace(1, p_align);
500 const file_size: u32 = 1;
501 log.debug("found PT_LOAD free space 0x{x} to 0x{x}", .{ off, off + file_size });
502 try self.program_headers.append(gpa, .{
503 .p_type = elf.PT_LOAD,
504 .p_offset = off,
505 .p_filesz = file_size,
506 .p_vaddr = phdr_addr,
507 .p_paddr = phdr_addr,
508 .p_memsz = file_size,
509 .p_align = p_align,
510 .p_flags = elf.PF_R,
511 });
512 self.phdr_table_dirty = true;
513 }
514
515 if (self.phdr_load_re_index == null) {
516 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
517 const file_size = self.base.options.program_code_size_hint;
518 const p_align = self.page_size;
519 const off = self.findFreeSpace(file_size, p_align);
520 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
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;
522 try self.program_headers.append(gpa, .{
523 .p_type = elf.PT_LOAD,
524 .p_offset = off,
525 .p_filesz = file_size,
526 .p_vaddr = entry_addr,
527 .p_paddr = entry_addr,
528 .p_memsz = file_size,
529 .p_align = p_align,
530 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
531 });
532 self.entry_addr = null;
533 self.phdr_table_dirty = true;
534 }
535
536 if (self.phdr_got_index == null) {
537 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
538 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
539 // We really only need ptr alignment but since we are using PROGBITS, linux requires
540 // page align.
541 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
542 const off = self.findFreeSpace(file_size, p_align);
543 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
544 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
545 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
546 // else in virtual memory.
547 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
548 try self.program_headers.append(gpa, .{
549 .p_type = elf.PT_LOAD,
550 .p_offset = off,
551 .p_filesz = file_size,
552 .p_vaddr = got_addr,
553 .p_paddr = got_addr,
554 .p_memsz = file_size,
555 .p_align = p_align,
556 .p_flags = elf.PF_R | elf.PF_W,
557 });
558 self.phdr_table_dirty = true;
559 }
560
561 if (self.phdr_load_ro_index == null) {
562 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
563 // TODO Find a hint about how much data need to be in rodata ?
564 const file_size = 1024;
565 // Same reason as for GOT
566 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
567 const off = self.findFreeSpace(file_size, p_align);
568 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
569 // TODO Same as for GOT
570 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
571 try self.program_headers.append(gpa, .{
572 .p_type = elf.PT_LOAD,
573 .p_offset = off,
574 .p_filesz = file_size,
575 .p_vaddr = rodata_addr,
576 .p_paddr = rodata_addr,
577 .p_memsz = file_size,
578 .p_align = p_align,
579 .p_flags = elf.PF_R | elf.PF_W,
580 });
581 self.phdr_table_dirty = true;
582 }
583
584 if (self.phdr_load_rw_index == null) {
585 self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
586 // TODO Find a hint about how much data need to be in data ?
587 const file_size = 1024;
588 // Same reason as for GOT
589 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
590 const off = self.findFreeSpace(file_size, p_align);
591 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
592 // TODO Same as for GOT
593 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
594 try self.program_headers.append(gpa, .{
595 .p_type = elf.PT_LOAD,
596 .p_offset = off,
597 .p_filesz = file_size,
598 .p_vaddr = rwdata_addr,
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 }
457 if (self.phdr_table_index == null) {
458 self.phdr_table_index = @intCast(u16, self.program_headers.items.len);
459 const p_align: u16 = switch (self.ptr_width) {
460 .p32 => @alignOf(elf.Elf32_Phdr),
461 .p64 => @alignOf(elf.Elf64_Phdr),
462 };
463 try self.program_headers.append(gpa, .{
464 .p_type = elf.PT_PHDR,
465 .p_offset = 0,
466 .p_filesz = 0,
467 .p_vaddr = 0,
468 .p_paddr = 0,
469 .p_memsz = 0,
470 .p_align = p_align,
471 .p_flags = elf.PF_R,
472 });
473 self.phdr_table_dirty = true;
474 }
475
476 if (self.phdr_table_load_index == null) {
477 self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
478 // TODO Same as for GOT
479 const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
480 const p_align = self.page_size;
481 try self.program_headers.append(gpa, .{
482 .p_type = elf.PT_LOAD,
483 .p_offset = 0,
484 .p_filesz = 0,
485 .p_vaddr = phdr_addr,
486 .p_paddr = phdr_addr,
487 .p_memsz = 0,
488 .p_align = p_align,
489 .p_flags = elf.PF_R,
490 });
491 self.phdr_table_dirty = true;
492 }
493
494 if (self.phdr_load_re_index == null) {
495 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
496 const file_size = self.base.options.program_code_size_hint;
497 const p_align = self.page_size;
498 const off = self.findFreeSpace(file_size, p_align);
499 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
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;
501 try self.program_headers.append(gpa, .{
502 .p_type = elf.PT_LOAD,
503 .p_offset = off,
504 .p_filesz = file_size,
505 .p_vaddr = entry_addr,
506 .p_paddr = entry_addr,
507 .p_memsz = file_size,
508 .p_align = p_align,
509 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
510 });
511 self.entry_addr = null;
512 self.phdr_table_dirty = true;
513 }
514
515 if (self.phdr_got_index == null) {
516 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
517 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
518 // We really only need ptr alignment but since we are using PROGBITS, linux requires
519 // page align.
520 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
521 const off = self.findFreeSpace(file_size, p_align);
522 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
523 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
524 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
525 // else in virtual memory.
526 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
527 try self.program_headers.append(gpa, .{
528 .p_type = elf.PT_LOAD,
529 .p_offset = off,
530 .p_filesz = file_size,
531 .p_vaddr = got_addr,
532 .p_paddr = got_addr,
533 .p_memsz = file_size,
534 .p_align = p_align,
535 .p_flags = elf.PF_R | elf.PF_W,
536 });
537 self.phdr_table_dirty = true;
538 }
539
540 if (self.phdr_load_ro_index == null) {
541 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
542 // TODO Find a hint about how much data need to be in rodata ?
543 const file_size = 1024;
544 // Same reason as for GOT
545 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
546 const off = self.findFreeSpace(file_size, p_align);
547 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
548 // TODO Same as for GOT
549 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
550 try self.program_headers.append(gpa, .{
551 .p_type = elf.PT_LOAD,
552 .p_offset = off,
553 .p_filesz = file_size,
554 .p_vaddr = rodata_addr,
555 .p_paddr = rodata_addr,
556 .p_memsz = file_size,
557 .p_align = p_align,
558 .p_flags = elf.PF_R | elf.PF_W,
559 });
560 self.phdr_table_dirty = true;
561 }
562
563 if (self.phdr_load_rw_index == null) {
564 self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
565 // TODO Find a hint about how much data need to be in data ?
566 const file_size = 1024;
567 // Same reason as for GOT
568 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
569 const off = self.findFreeSpace(file_size, p_align);
570 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
571 // TODO Same as for GOT
572 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
573 try self.program_headers.append(gpa, .{
574 .p_type = elf.PT_LOAD,
575 .p_offset = off,
576 .p_filesz = file_size,
577 .p_vaddr = rwdata_addr,
578 .p_paddr = rwdata_addr,
579 .p_memsz = file_size,
580 .p_align = p_align,
581 .p_flags = elf.PF_R | elf.PF_W,
582 });
583 self.phdr_table_dirty = true;
617584 }
618585
619586 if (self.shstrtab_index == null) {
......@@ -1186,8 +1153,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11861153 const needed_size = self.program_headers.items.len * phsize;
11871154
11881155 if (needed_size > allocated_size) {
1189 self.phdr_table_index = null; // free the space
1190 defer self.phdr_table_index = phdr_table_index;
1156 phdr_table.p_offset = 0; // free the space
11911157 phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));
11921158 }
11931159
......@@ -1227,6 +1193,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12271193 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
12281194 },
12291195 }
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
12301201 self.phdr_table_dirty = false;
12311202 }
12321203