authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-09 13:22:50+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-09 13:22:50+01:00
logec3e638b97c638a6d292902b18a6a685854d60b4
tree0366b7da81517db151e2b20490cd787e0479ec45
parente588e3873cdb4a7f8e03085d83453f9f3d5e36a7

elf: fix unaligned file offset of moved phdr containing GOT section


1 files changed, 39 insertions(+), 15 deletions(-)

src/link/Elf.zig+39-15
......@@ -2,6 +2,7 @@ const Elf = @This();
22
33const std = @import("std");
44const builtin = @import("builtin");
5const math = std.math;
56const mem = std.mem;
67const assert = std.debug.assert;
78const Allocator = std.mem.Allocator;
......@@ -64,6 +65,7 @@ phdr_load_rw_index: ?u16 = null,
6465phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
6566
6667entry_addr: ?u64 = null,
68page_size: u16,
6769
6870debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
6971shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
......@@ -334,6 +336,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
334336 };
335337 const self = try gpa.create(Elf);
336338 errdefer gpa.destroy(self);
339 const page_size: u16 = 0x1000; // TODO ppc64le requires 64KB
337340
338341 self.* = .{
339342 .base = .{
......@@ -343,6 +346,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
343346 .file = null,
344347 },
345348 .ptr_width = ptr_width,
349 .page_size = page_size,
346350 };
347351 const use_llvm = build_options.have_llvm and options.use_llvm;
348352 const use_stage1 = build_options.is_stage1 and options.use_stage1;
......@@ -523,10 +527,11 @@ pub fn populateMissingMetadata(self: *Elf) !void {
523527 .p64 => false,
524528 };
525529 const ptr_size: u8 = self.ptrWidthBytes();
530
526531 if (self.phdr_load_re_index == null) {
527532 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
528533 const file_size = self.base.options.program_code_size_hint;
529 const p_align = 0x1000;
534 const p_align = self.page_size;
530535 const off = self.findFreeSpace(file_size, p_align);
531536 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
532537 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
......@@ -544,12 +549,13 @@ pub fn populateMissingMetadata(self: *Elf) !void {
544549 self.entry_addr = null;
545550 self.phdr_table_dirty = true;
546551 }
552
547553 if (self.phdr_got_index == null) {
548554 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
549555 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
550556 // We really only need ptr alignment but since we are using PROGBITS, linux requires
551557 // page align.
552 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
558 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
553559 const off = self.findFreeSpace(file_size, p_align);
554560 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
555561 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
......@@ -568,16 +574,17 @@ pub fn populateMissingMetadata(self: *Elf) !void {
568574 });
569575 self.phdr_table_dirty = true;
570576 }
577
571578 if (self.phdr_load_ro_index == null) {
572579 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
573580 // TODO Find a hint about how much data need to be in rodata ?
574581 const file_size = 1024;
575582 // Same reason as for GOT
576 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
583 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
577584 const off = self.findFreeSpace(file_size, p_align);
578 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
585 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
579586 // TODO Same as for GOT
580 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x5000000 else 0xa000;
587 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
581588 try self.program_headers.append(self.base.allocator, .{
582589 .p_type = elf.PT_LOAD,
583590 .p_offset = off,
......@@ -591,16 +598,17 @@ pub fn populateMissingMetadata(self: *Elf) !void {
591598 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{});
592599 self.phdr_table_dirty = true;
593600 }
601
594602 if (self.phdr_load_rw_index == null) {
595603 self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
596604 // TODO Find a hint about how much data need to be in data ?
597605 const file_size = 1024;
598606 // Same reason as for GOT
599 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
607 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
600608 const off = self.findFreeSpace(file_size, p_align);
601 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
609 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
602610 // TODO Same as for GOT
603 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x6000000 else 0xc000;
611 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
604612 try self.program_headers.append(self.base.allocator, .{
605613 .p_type = elf.PT_LOAD,
606614 .p_offset = off,
......@@ -614,6 +622,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
614622 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{});
615623 self.phdr_table_dirty = true;
616624 }
625
617626 if (self.shstrtab_index == null) {
618627 self.shstrtab_index = @intCast(u16, self.sections.items.len);
619628 assert(self.shstrtab.items.len == 0);
......@@ -635,6 +644,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
635644 self.shstrtab_dirty = true;
636645 self.shdr_table_dirty = true;
637646 }
647
638648 if (self.text_section_index == null) {
639649 self.text_section_index = @intCast(u16, self.sections.items.len);
640650 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
......@@ -648,7 +658,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
648658 .sh_size = phdr.p_filesz,
649659 .sh_link = 0,
650660 .sh_info = 0,
651 .sh_addralign = phdr.p_align,
661 .sh_addralign = 1,
652662 .sh_entsize = 0,
653663 });
654664 try self.phdr_shdr_table.putNoClobber(
......@@ -658,6 +668,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
658668 );
659669 self.shdr_table_dirty = true;
660670 }
671
661672 if (self.got_section_index == null) {
662673 self.got_section_index = @intCast(u16, self.sections.items.len);
663674 const phdr = &self.program_headers.items[self.phdr_got_index.?];
......@@ -671,7 +682,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
671682 .sh_size = phdr.p_filesz,
672683 .sh_link = 0,
673684 .sh_info = 0,
674 .sh_addralign = phdr.p_align,
685 .sh_addralign = @as(u16, ptr_size),
675686 .sh_entsize = 0,
676687 });
677688 try self.phdr_shdr_table.putNoClobber(
......@@ -681,6 +692,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
681692 );
682693 self.shdr_table_dirty = true;
683694 }
695
684696 if (self.rodata_section_index == null) {
685697 self.rodata_section_index = @intCast(u16, self.sections.items.len);
686698 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
......@@ -694,7 +706,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
694706 .sh_size = phdr.p_filesz,
695707 .sh_link = 0,
696708 .sh_info = 0,
697 .sh_addralign = phdr.p_align,
709 .sh_addralign = 1,
698710 .sh_entsize = 0,
699711 });
700712 try self.phdr_shdr_table.putNoClobber(
......@@ -704,6 +716,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
704716 );
705717 self.shdr_table_dirty = true;
706718 }
719
707720 if (self.data_section_index == null) {
708721 self.data_section_index = @intCast(u16, self.sections.items.len);
709722 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];
......@@ -717,7 +730,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
717730 .sh_size = phdr.p_filesz,
718731 .sh_link = 0,
719732 .sh_info = 0,
720 .sh_addralign = phdr.p_align,
733 .sh_addralign = @as(u16, ptr_size),
721734 .sh_entsize = 0,
722735 });
723736 try self.phdr_shdr_table.putNoClobber(
......@@ -727,6 +740,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
727740 );
728741 self.shdr_table_dirty = true;
729742 }
743
730744 if (self.symtab_section_index == null) {
731745 self.symtab_section_index = @intCast(u16, self.sections.items.len);
732746 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
......@@ -751,6 +765,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
751765 self.shdr_table_dirty = true;
752766 try self.writeSymbol(0);
753767 }
768
754769 if (self.debug_str_section_index == null) {
755770 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
756771 assert(self.debug_strtab.items.len == 0);
......@@ -769,6 +784,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
769784 self.debug_strtab_dirty = true;
770785 self.shdr_table_dirty = true;
771786 }
787
772788 if (self.debug_info_section_index == null) {
773789 self.debug_info_section_index = @intCast(u16, self.sections.items.len);
774790
......@@ -794,6 +810,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
794810 self.shdr_table_dirty = true;
795811 self.debug_info_header_dirty = true;
796812 }
813
797814 if (self.debug_abbrev_section_index == null) {
798815 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
799816
......@@ -819,6 +836,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
819836 self.shdr_table_dirty = true;
820837 self.debug_abbrev_section_dirty = true;
821838 }
839
822840 if (self.debug_aranges_section_index == null) {
823841 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
824842
......@@ -844,6 +862,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
844862 self.shdr_table_dirty = true;
845863 self.debug_aranges_section_dirty = true;
846864 }
865
847866 if (self.debug_line_section_index == null) {
848867 self.debug_line_section_index = @intCast(u16, self.sections.items.len);
849868
......@@ -869,6 +888,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
869888 self.shdr_table_dirty = true;
870889 self.debug_line_header_dirty = true;
871890 }
891
872892 const shsize: u64 = switch (self.ptr_width) {
873893 .p32 => @sizeOf(elf.Elf32_Shdr),
874894 .p64 => @sizeOf(elf.Elf64_Shdr),
......@@ -881,6 +901,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
881901 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
882902 self.shdr_table_dirty = true;
883903 }
904
884905 const phsize: u64 = switch (self.ptr_width) {
885906 .p32 => @sizeOf(elf.Elf32_Phdr),
886907 .p64 => @sizeOf(elf.Elf64_Phdr),
......@@ -893,6 +914,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
893914 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);
894915 self.phdr_table_dirty = true;
895916 }
917
896918 {
897919 // Iterate over symbols, populating free_list and last_text_block.
898920 if (self.local_symbols.items.len != 1) {
......@@ -2378,12 +2400,13 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
23782400 const text_capacity = self.allocatedSize(shdr.sh_offset);
23792401 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
23802402 if (needed_size > text_capacity) {
2381 // Must move the entire text section.
2382 const new_offset = self.findFreeSpace(needed_size, 0x1000);
2403 // Must move the entire section.
2404 const new_offset = self.findFreeSpace(needed_size, self.page_size);
23832405 const text_size = if (self.atoms.get(phdr_index)) |last| blk: {
23842406 const sym = self.local_symbols.items[last.local_sym_index];
23852407 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
23862408 } else 0;
2409 log.debug("new PT_LOAD file offset 0x{x} to 0x{x}", .{ new_offset, new_offset + text_size });
23872410 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size);
23882411 if (amt != text_size) return error.InputOutput;
23892412 shdr.sh_offset = new_offset;
......@@ -2407,6 +2430,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
24072430 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
24082431 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
24092432 }
2433 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);
24102434
24112435 // This function can also reallocate a text block.
24122436 // In this case we need to "unplug" it from its previous location before
......@@ -3478,7 +3502,7 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
34783502 const needed_size = self.offset_table.items.len * entry_size;
34793503 if (needed_size > allocated_size) {
34803504 // Must move the entire got section.
3481 const new_offset = self.findFreeSpace(needed_size, entry_size);
3505 const new_offset = self.findFreeSpace(needed_size, self.page_size);
34823506 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size);
34833507 if (amt != shdr.sh_size) return error.InputOutput;
34843508 shdr.sh_offset = new_offset;