| ... | ... | @@ -47,6 +47,10 @@ phdr_load_zerofill_zig_index: ?u16 = null, |
| 47 | 47 | /// Special program headers |
| 48 | 48 | /// PT_PHDR |
| 49 | 49 | phdr_table_index: ?u16 = null, |
| 50 | /// PT_LOAD for PHDR table |
| 51 | /// We add this special load segment to ensure the PHDR table is always |
| 52 | /// loaded into memory. |
| 53 | phdr_table_load_index: ?u16 = null, |
| 50 | 54 | /// PT_INTERP |
| 51 | 55 | phdr_interp_index: ?u16 = null, |
| 52 | 56 | /// PT_DYNAMIC |
| ... | ... | @@ -281,6 +285,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 281 | 285 | .p32 => @alignOf(elf.Elf32_Phdr), |
| 282 | 286 | .p64 => @alignOf(elf.Elf64_Phdr), |
| 283 | 287 | }; |
| 288 | const image_base = self.calcImageBase(); |
| 284 | 289 | const offset: u64 = switch (self.ptr_width) { |
| 285 | 290 | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 286 | 291 | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| ... | ... | @@ -289,9 +294,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 289 | 294 | .type = elf.PT_PHDR, |
| 290 | 295 | .flags = elf.PF_R, |
| 291 | 296 | .@"align" = p_align, |
| 292 | | .addr = self.calcImageBase() + offset, |
| 297 | .addr = image_base + offset, |
| 293 | 298 | .offset = offset, |
| 294 | 299 | }); |
| 300 | self.phdr_table_load_index = try self.addPhdr(.{ |
| 301 | .type = elf.PT_LOAD, |
| 302 | .flags = elf.PF_R, |
| 303 | .@"align" = self.page_size, |
| 304 | .addr = image_base, |
| 305 | }); |
| 295 | 306 | } |
| 296 | 307 | |
| 297 | 308 | if (options.module != null and !options.use_llvm) { |
| ... | ... | @@ -571,34 +582,23 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 571 | 582 | } |
| 572 | 583 | |
| 573 | 584 | const AllocateSegmentOpts = struct { |
| 585 | addr: u64, |
| 574 | 586 | size: u64, |
| 575 | 587 | alignment: u64, |
| 576 | | addr: ?u64 = null, |
| 577 | 588 | flags: u32 = elf.PF_R, |
| 578 | 589 | }; |
| 579 | 590 | |
| 580 | 591 | pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 { |
| 581 | | const gpa = self.base.allocator; |
| 582 | | const index = @as(u16, @intCast(self.phdrs.items.len)); |
| 583 | | try self.phdrs.ensureUnusedCapacity(gpa, 1); |
| 584 | 592 | const off = self.findFreeSpace(opts.size, opts.alignment); |
| 585 | | // Currently, we automatically allocate memory in sequence by finding the largest |
| 586 | | // allocated virtual address and going from there. |
| 587 | | // TODO we want to keep machine code segment in the furthest memory range among all |
| 588 | | // segments as it is most likely to grow. |
| 589 | | const addr = opts.addr orelse blk: { |
| 590 | | const reserved_capacity = self.calcImageBase() * 4; |
| 591 | | // Calculate largest VM address |
| 592 | | var addresses = std.ArrayList(u64).init(gpa); |
| 593 | | defer addresses.deinit(); |
| 594 | | try addresses.ensureTotalCapacityPrecise(self.phdrs.items.len); |
| 595 | | for (self.phdrs.items) |phdr| { |
| 596 | | if (phdr.p_type != elf.PT_LOAD) continue; |
| 597 | | addresses.appendAssumeCapacity(phdr.p_vaddr + reserved_capacity); |
| 598 | | } |
| 599 | | mem.sort(u64, addresses.items, {}, std.sort.asc(u64)); |
| 600 | | break :blk mem.alignForward(u64, addresses.pop(), opts.alignment); |
| 601 | | }; |
| 593 | const index = try self.addPhdr(.{ |
| 594 | .type = elf.PT_LOAD, |
| 595 | .offset = off, |
| 596 | .filesz = opts.size, |
| 597 | .addr = opts.addr, |
| 598 | .memsz = opts.size, |
| 599 | .@"align" = opts.alignment, |
| 600 | .flags = opts.flags, |
| 601 | }); |
| 602 | 602 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 603 | 603 | index, |
| 604 | 604 | if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_', |
| ... | ... | @@ -606,18 +606,8 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory} |
| 606 | 606 | if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_', |
| 607 | 607 | off, |
| 608 | 608 | off + opts.size, |
| 609 | | addr, |
| 610 | | addr + opts.size, |
| 611 | | }); |
| 612 | | self.phdrs.appendAssumeCapacity(.{ |
| 613 | | .p_type = elf.PT_LOAD, |
| 614 | | .p_offset = off, |
| 615 | | .p_filesz = opts.size, |
| 616 | | .p_vaddr = addr, |
| 617 | | .p_paddr = addr, |
| 618 | | .p_memsz = opts.size, |
| 619 | | .p_align = opts.alignment, |
| 620 | | .p_flags = opts.flags, |
| 609 | opts.addr, |
| 610 | opts.addr + opts.size, |
| 621 | 611 | }); |
| 622 | 612 | return index; |
| 623 | 613 | } |
| ... | ... | @@ -687,11 +677,13 @@ fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{ |
| 687 | 677 | /// TODO move to ZigModule |
| 688 | 678 | pub fn initMetadata(self: *Elf) !void { |
| 689 | 679 | const gpa = self.base.allocator; |
| 690 | | const ptr_size: u8 = self.ptrWidthBytes(); |
| 680 | const ptr_size = self.ptrWidthBytes(); |
| 681 | const ptr_bit_width = self.base.options.target.ptrBitWidth(); |
| 691 | 682 | const is_linux = self.base.options.target.os.tag == .linux; |
| 692 | 683 | |
| 693 | 684 | if (self.phdr_load_re_zig_index == null) { |
| 694 | 685 | self.phdr_load_re_zig_index = try self.allocateSegment(.{ |
| 686 | .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000, |
| 695 | 687 | .size = self.base.options.program_code_size_hint, |
| 696 | 688 | .alignment = self.page_size, |
| 697 | 689 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| ... | ... | @@ -703,6 +695,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 703 | 695 | // page align. |
| 704 | 696 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 705 | 697 | self.phdr_got_zig_index = try self.allocateSegment(.{ |
| 698 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, |
| 706 | 699 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 707 | 700 | .alignment = alignment, |
| 708 | 701 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -712,6 +705,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 712 | 705 | if (self.phdr_load_ro_zig_index == null) { |
| 713 | 706 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 714 | 707 | self.phdr_load_ro_zig_index = try self.allocateSegment(.{ |
| 708 | .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000, |
| 715 | 709 | .size = 1024, |
| 716 | 710 | .alignment = alignment, |
| 717 | 711 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -721,6 +715,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 721 | 715 | if (self.phdr_load_rw_zig_index == null) { |
| 722 | 716 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 723 | 717 | self.phdr_load_rw_zig_index = try self.allocateSegment(.{ |
| 718 | .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000, |
| 724 | 719 | .size = 1024, |
| 725 | 720 | .alignment = alignment, |
| 726 | 721 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -730,6 +725,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 730 | 725 | if (self.phdr_load_zerofill_zig_index == null) { |
| 731 | 726 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 732 | 727 | self.phdr_load_zerofill_zig_index = try self.allocateSegment(.{ |
| 728 | .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000, |
| 733 | 729 | .size = 0, |
| 734 | 730 | .alignment = alignment, |
| 735 | 731 | .flags = elf.PF_R | elf.PF_W, |
| ... | ... | @@ -2820,10 +2816,18 @@ fn writePhdrTable(self: *Elf) !void { |
| 2820 | 2816 | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 2821 | 2817 | }; |
| 2822 | 2818 | const phdr_table = &self.phdrs.items[self.phdr_table_index.?]; |
| 2819 | const phdr_segment = &self.phdrs.items[self.phdr_table_load_index.?]; |
| 2823 | 2820 | const needed_size = self.phdrs.items.len * phsize; |
| 2824 | 2821 | phdr_table.p_filesz = needed_size; |
| 2825 | 2822 | phdr_table.p_memsz = needed_size; |
| 2826 | 2823 | |
| 2824 | const ehsize: u64 = switch (self.ptr_width) { |
| 2825 | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 2826 | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 2827 | }; |
| 2828 | phdr_segment.p_filesz = needed_size + ehsize; |
| 2829 | phdr_segment.p_memsz = needed_size + ehsize; |
| 2830 | |
| 2827 | 2831 | log.debug("writing program headers from 0x{x} to 0x{x}", .{ |
| 2828 | 2832 | phdr_table.p_offset, |
| 2829 | 2833 | phdr_table.p_offset + needed_size, |
| ... | ... | @@ -4387,6 +4391,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4387 | 4391 | |
| 4388 | 4392 | /// The assumed layout of PHDRs in file is as follows: |
| 4389 | 4393 | /// PT_PHDR |
| 4394 | /// PT_LOAD for PT_PHDR |
| 4390 | 4395 | /// PT_INTERP |
| 4391 | 4396 | /// PT_DYNAMIC |
| 4392 | 4397 | /// PT_GNU_EH_FRAME |
| ... | ... | @@ -4399,7 +4404,8 @@ fn resetPhdrs(self: *Elf) !void { |
| 4399 | 4404 | try self.phdrs.ensureUnusedCapacity(gpa, phdrs.len); |
| 4400 | 4405 | |
| 4401 | 4406 | for (&[_]?u16{ |
| 4402 | | self.phdr_table_index.?, |
| 4407 | self.phdr_table_index, |
| 4408 | self.phdr_table_load_index, |
| 4403 | 4409 | self.phdr_interp_index, |
| 4404 | 4410 | self.phdr_dynamic_index, |
| 4405 | 4411 | self.phdr_gnu_eh_frame_index, |
| ... | ... | @@ -4636,9 +4642,17 @@ fn allocateSectionsInFile(self: *Elf, base_offset: u64) void { |
| 4636 | 4642 | } |
| 4637 | 4643 | |
| 4638 | 4644 | fn allocateSections(self: *Elf) !void { |
| 4645 | const ehsize: u64 = switch (self.ptr_width) { |
| 4646 | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 4647 | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 4648 | }; |
| 4649 | const phsize: u64 = switch (self.ptr_width) { |
| 4650 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 4651 | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 4652 | }; |
| 4639 | 4653 | while (true) { |
| 4640 | 4654 | const nphdrs = self.phdrs.items.len; |
| 4641 | | const base_offset: u64 = @sizeOf(elf.Elf64_Ehdr) + nphdrs * @sizeOf(elf.Elf64_Phdr); |
| 4655 | const base_offset: u64 = ehsize + nphdrs * phsize; |
| 4642 | 4656 | self.allocateSectionsInMemory(base_offset); |
| 4643 | 4657 | self.allocateSectionsInFile(base_offset); |
| 4644 | 4658 | try self.resetPhdrs(); |
| ... | ... | @@ -4663,14 +4677,6 @@ fn allocateSpecialPhdrs(self: *Elf) void { |
| 4663 | 4677 | phdr.p_memsz = shdr.sh_size; |
| 4664 | 4678 | } |
| 4665 | 4679 | } |
| 4666 | | |
| 4667 | | { |
| 4668 | | // Backpatch size of the PHDR phdr |
| 4669 | | const phdr = &self.phdrs.items[self.phdr_table_index.?]; |
| 4670 | | const size = @sizeOf(elf.Elf64_Phdr) * self.phdrs.items.len; |
| 4671 | | phdr.p_filesz = size; |
| 4672 | | phdr.p_memsz = size; |
| 4673 | | } |
| 4674 | 4680 | } |
| 4675 | 4681 | |
| 4676 | 4682 | fn allocateAtoms(self: *Elf) void { |
| ... | ... | @@ -5341,7 +5347,7 @@ fn addPhdr(self: *Elf, opts: struct { |
| 5341 | 5347 | addr: u64 = 0, |
| 5342 | 5348 | filesz: u64 = 0, |
| 5343 | 5349 | memsz: u64 = 0, |
| 5344 | | }) !u16 { |
| 5350 | }) error{OutOfMemory}!u16 { |
| 5345 | 5351 | const index = @as(u16, @intCast(self.phdrs.items.len)); |
| 5346 | 5352 | try self.phdrs.append(self.base.allocator, .{ |
| 5347 | 5353 | .p_type = opts.type, |