| ... | ... | @@ -542,21 +542,23 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 542 | 542 | } |
| 543 | 543 | |
| 544 | 544 | for (self.shdrs.items) |shdr| { |
| 545 | | // SHT_NOBITS takes no physical space in the output file so set its size to 0. |
| 546 | | const sh_size = if (shdr.sh_type == elf.SHT_NOBITS) 0 else shdr.sh_size; |
| 547 | | const increased_size = padToIdeal(sh_size); |
| 545 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 546 | const increased_size = padToIdeal(shdr.sh_size); |
| 548 | 547 | const test_end = shdr.sh_offset + increased_size; |
| 549 | 548 | if (end > shdr.sh_offset and start < test_end) { |
| 550 | 549 | return test_end; |
| 551 | 550 | } |
| 552 | 551 | } |
| 552 | |
| 553 | 553 | for (self.phdrs.items) |phdr| { |
| 554 | if (phdr.p_type != elf.PT_LOAD) continue; |
| 554 | 555 | const increased_size = padToIdeal(phdr.p_filesz); |
| 555 | 556 | const test_end = phdr.p_offset + increased_size; |
| 556 | 557 | if (end > phdr.p_offset and start < test_end) { |
| 557 | 558 | return test_end; |
| 558 | 559 | } |
| 559 | 560 | } |
| 561 | |
| 560 | 562 | return null; |
| 561 | 563 | } |
| 562 | 564 | |
| ... | ... | @@ -597,19 +599,20 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 597 | 599 | |
| 598 | 600 | const AllocateSegmentOpts = struct { |
| 599 | 601 | addr: u64, |
| 600 | | size: u64, |
| 602 | memsz: u64, |
| 603 | filesz: u64, |
| 601 | 604 | alignment: u64, |
| 602 | 605 | flags: u32 = elf.PF_R, |
| 603 | 606 | }; |
| 604 | 607 | |
| 605 | 608 | pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 { |
| 606 | | const off = self.findFreeSpace(opts.size, opts.alignment); |
| 609 | const off = self.findFreeSpace(opts.filesz, opts.alignment); |
| 607 | 610 | const index = try self.addPhdr(.{ |
| 608 | 611 | .type = elf.PT_LOAD, |
| 609 | 612 | .offset = off, |
| 610 | | .filesz = opts.size, |
| 613 | .filesz = opts.filesz, |
| 611 | 614 | .addr = opts.addr, |
| 612 | | .memsz = opts.size, |
| 615 | .memsz = opts.memsz, |
| 613 | 616 | .@"align" = opts.alignment, |
| 614 | 617 | .flags = opts.flags, |
| 615 | 618 | }); |
| ... | ... | @@ -619,9 +622,9 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory} |
| 619 | 622 | if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_', |
| 620 | 623 | if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_', |
| 621 | 624 | off, |
| 622 | | off + opts.size, |
| 625 | off + opts.filesz, |
| 623 | 626 | opts.addr, |
| 624 | | opts.addr + opts.size, |
| 627 | opts.addr + opts.memsz, |
| 625 | 628 | }); |
| 626 | 629 | return index; |
| 627 | 630 | } |
| ... | ... | @@ -698,7 +701,8 @@ pub fn initMetadata(self: *Elf) !void { |
| 698 | 701 | if (self.phdr_load_re_zig_index == null) { |
| 699 | 702 | self.phdr_load_re_zig_index = try self.allocateSegment(.{ |
| 700 | 703 | .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000, |
| 701 | | .size = self.base.options.program_code_size_hint, |
| 704 | .memsz = self.base.options.program_code_size_hint, |
| 705 | .filesz = self.base.options.program_code_size_hint, |
| 702 | 706 | .alignment = self.page_size, |
| 703 | 707 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| 704 | 708 | }); |
| ... | ... | @@ -710,7 +714,8 @@ pub fn initMetadata(self: *Elf) !void { |
| 710 | 714 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 711 | 715 | self.phdr_got_zig_index = try self.allocateSegment(.{ |
| 712 | 716 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, |
| 713 | | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 717 | .memsz = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 718 | .filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 714 | 719 | .alignment = alignment, |
| 715 | 720 | .flags = elf.PF_R | elf.PF_W, |
| 716 | 721 | }); |
| ... | ... | @@ -720,7 +725,8 @@ pub fn initMetadata(self: *Elf) !void { |
| 720 | 725 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 721 | 726 | self.phdr_load_ro_zig_index = try self.allocateSegment(.{ |
| 722 | 727 | .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000, |
| 723 | | .size = 1024, |
| 728 | .memsz = 1024, |
| 729 | .filesz = 1024, |
| 724 | 730 | .alignment = alignment, |
| 725 | 731 | .flags = elf.PF_R | elf.PF_W, |
| 726 | 732 | }); |
| ... | ... | @@ -730,7 +736,8 @@ pub fn initMetadata(self: *Elf) !void { |
| 730 | 736 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 731 | 737 | self.phdr_load_rw_zig_index = try self.allocateSegment(.{ |
| 732 | 738 | .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000, |
| 733 | | .size = 1024, |
| 739 | .memsz = 1024, |
| 740 | .filesz = 1024, |
| 734 | 741 | .alignment = alignment, |
| 735 | 742 | .flags = elf.PF_R | elf.PF_W, |
| 736 | 743 | }); |
| ... | ... | @@ -740,7 +747,8 @@ pub fn initMetadata(self: *Elf) !void { |
| 740 | 747 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 741 | 748 | self.phdr_load_zerofill_zig_index = try self.allocateSegment(.{ |
| 742 | 749 | .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000, |
| 743 | | .size = 0, |
| 750 | .memsz = 0, |
| 751 | .filesz = 0, |
| 744 | 752 | .alignment = alignment, |
| 745 | 753 | .flags = elf.PF_R | elf.PF_W, |
| 746 | 754 | }); |
| ... | ... | @@ -1602,7 +1610,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1602 | 1610 | try self.setVersionSymtab(); |
| 1603 | 1611 | try self.updateSectionSizes(); |
| 1604 | 1612 | |
| 1605 | | try self.initAndAllocateSegments(); |
| 1613 | // Allocate PHDR table. |
| 1614 | { |
| 1615 | const new_load_segments = self.calcNumberOfSegments(); |
| 1616 | const phdr_table = &self.phdrs.items[self.phdr_table_index.?]; |
| 1617 | const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?]; |
| 1618 | |
| 1619 | const phsize: u64 = switch (self.ptr_width) { |
| 1620 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 1621 | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 1622 | }; |
| 1623 | const needed_size = (self.phdrs.items.len + new_load_segments) * phsize; |
| 1624 | |
| 1625 | if (needed_size > self.allocatedSize(phdr_table.p_offset)) { |
| 1626 | phdr_table.p_offset = 0; |
| 1627 | phdr_table.p_offset = self.findFreeSpace(needed_size, phdr_table.p_align); |
| 1628 | } |
| 1629 | |
| 1630 | phdr_table_load.p_offset = mem.alignBackward(u64, phdr_table.p_offset, phdr_table_load.p_align); |
| 1631 | const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset; |
| 1632 | phdr_table_load.p_filesz = load_align_offset + needed_size; |
| 1633 | phdr_table_load.p_memsz = load_align_offset + needed_size; |
| 1634 | |
| 1635 | phdr_table.p_filesz = needed_size; |
| 1636 | phdr_table.p_vaddr = phdr_table_load.p_vaddr + load_align_offset; |
| 1637 | phdr_table.p_paddr = phdr_table_load.p_paddr + load_align_offset; |
| 1638 | phdr_table.p_memsz = needed_size; |
| 1639 | } |
| 1640 | |
| 1641 | try self.allocateAllocSections(); |
| 1606 | 1642 | self.allocateNonAllocSections(); |
| 1607 | 1643 | self.allocateSpecialPhdrs(); |
| 1608 | 1644 | self.allocateAtoms(); |
| ... | ... | @@ -2832,26 +2868,11 @@ fn writePhdrTable(self: *Elf) !void { |
| 2832 | 2868 | const gpa = self.base.allocator; |
| 2833 | 2869 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 2834 | 2870 | const foreign_endian = target_endian != builtin.cpu.arch.endian(); |
| 2835 | | const phsize: u64 = switch (self.ptr_width) { |
| 2836 | | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 2837 | | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 2838 | | }; |
| 2839 | 2871 | const phdr_table = &self.phdrs.items[self.phdr_table_index.?]; |
| 2840 | | const phdr_segment = &self.phdrs.items[self.phdr_table_load_index.?]; |
| 2841 | | const needed_size = self.phdrs.items.len * phsize; |
| 2842 | | phdr_table.p_filesz = needed_size; |
| 2843 | | phdr_table.p_memsz = needed_size; |
| 2844 | | |
| 2845 | | const ehsize: u64 = switch (self.ptr_width) { |
| 2846 | | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 2847 | | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 2848 | | }; |
| 2849 | | phdr_segment.p_filesz = needed_size + ehsize; |
| 2850 | | phdr_segment.p_memsz = needed_size + ehsize; |
| 2851 | 2872 | |
| 2852 | 2873 | log.debug("writing program headers from 0x{x} to 0x{x}", .{ |
| 2853 | 2874 | phdr_table.p_offset, |
| 2854 | | phdr_table.p_offset + needed_size, |
| 2875 | phdr_table.p_offset + phdr_table.p_filesz, |
| 2855 | 2876 | }); |
| 2856 | 2877 | |
| 2857 | 2878 | switch (self.ptr_width) { |
| ... | ... | @@ -4454,7 +4475,6 @@ fn initSegments(self: *Elf) !void { |
| 4454 | 4475 | // Add LOAD phdrs |
| 4455 | 4476 | const gpa = self.base.allocator; |
| 4456 | 4477 | const slice = self.shdrs.items; |
| 4457 | | var is_first = true; |
| 4458 | 4478 | var shndx: u16 = 0; |
| 4459 | 4479 | while (shndx < slice.len) { |
| 4460 | 4480 | const shdr = &slice[shndx]; |
| ... | ... | @@ -4466,10 +4486,9 @@ fn initSegments(self: *Elf) !void { |
| 4466 | 4486 | .type = elf.PT_LOAD, |
| 4467 | 4487 | .flags = shdrToPhdrFlags(shdr.sh_flags), |
| 4468 | 4488 | .@"align" = @max(self.page_size, shdr.sh_addralign), |
| 4469 | | .offset = if (is_first) 0 else shdr.sh_offset, |
| 4470 | | .addr = if (is_first) self.calcImageBase() else shdr.sh_addr, |
| 4489 | .offset = shdr.sh_offset, |
| 4490 | .addr = shdr.sh_addr, |
| 4471 | 4491 | }); |
| 4472 | | is_first = false; |
| 4473 | 4492 | const p_flags = self.phdrs.items[phndx].p_flags; |
| 4474 | 4493 | self.addShdrToPhdr(shndx, phndx); |
| 4475 | 4494 | try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx); |
| ... | ... | @@ -4495,7 +4514,7 @@ fn addShdrToPhdr(self: *Elf, shdr_index: u16, phdr_index: u16) void { |
| 4495 | 4514 | const phdr = &self.phdrs.items[phdr_index]; |
| 4496 | 4515 | phdr.p_align = @max(phdr.p_align, shdr.sh_addralign); |
| 4497 | 4516 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 4498 | | phdr.p_filesz = shdr.sh_addr + shdr.sh_size - phdr.p_vaddr; |
| 4517 | phdr.p_filesz = shdr.sh_offset + shdr.sh_size - phdr.p_offset; |
| 4499 | 4518 | } |
| 4500 | 4519 | phdr.p_memsz = shdr.sh_addr + shdr.sh_size - phdr.p_vaddr; |
| 4501 | 4520 | } |
| ... | ... | @@ -4529,6 +4548,18 @@ pub inline fn shdrIsTls(shdr: *const elf.Elf64_Shdr) bool { |
| 4529 | 4548 | return shdr.sh_flags & elf.SHF_TLS != 0; |
| 4530 | 4549 | } |
| 4531 | 4550 | |
| 4551 | fn calcNumberOfSegments(self: *Elf) usize { |
| 4552 | var count: usize = 0; |
| 4553 | var flags: u64 = 0; |
| 4554 | for (self.shdrs.items) |shdr| { |
| 4555 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4556 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4557 | if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1; |
| 4558 | flags = shdrToPhdrFlags(shdr.sh_flags); |
| 4559 | } |
| 4560 | return count; |
| 4561 | } |
| 4562 | |
| 4532 | 4563 | fn allocateAllocSectionsInMemory(self: *Elf, base_addr: u64) void { |
| 4533 | 4564 | // We use this struct to track maximum alignment of all TLS sections. |
| 4534 | 4565 | // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold, |
| ... | ... | @@ -4649,28 +4680,150 @@ fn allocateAllocSectionsInFile(self: *Elf, base_offset: u64) void { |
| 4649 | 4680 | /// As a base address we take space immediately after the PHDR table, and |
| 4650 | 4681 | /// aim for fitting between it and where the first incremental segment is |
| 4651 | 4682 | /// allocated (see `initMetadata`). |
| 4652 | | fn initAndAllocateSegments(self: *Elf) !void { |
| 4653 | | const ehsize: u64 = switch (self.ptr_width) { |
| 4654 | | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 4655 | | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 4656 | | }; |
| 4657 | | const phsize: u64 = switch (self.ptr_width) { |
| 4658 | | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 4659 | | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 4660 | | }; |
| 4661 | | const image_base = self.calcImageBase(); |
| 4683 | fn initAndAllocateSegments(self: *Elf, base_addr: u64, base_offset: u64) !void { |
| 4662 | 4684 | while (true) { |
| 4663 | 4685 | const nphdrs = self.phdrs.items.len; |
| 4664 | | const off = ehsize + nphdrs * phsize; |
| 4665 | | const addr = image_base + off; |
| 4666 | | self.allocateAllocSectionsInMemory(addr); |
| 4667 | | self.allocateAllocSectionsInFile(off); |
| 4686 | self.allocateAllocSectionsInMemory(base_addr); |
| 4687 | self.allocateAllocSectionsInFile(base_offset); |
| 4668 | 4688 | try self.resetPhdrs(); |
| 4669 | 4689 | try self.initSegments(); |
| 4670 | 4690 | if (nphdrs == self.phdrs.items.len) break; |
| 4671 | 4691 | } |
| 4672 | 4692 | } |
| 4673 | 4693 | |
| 4694 | fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4695 | // We use this struct to track maximum alignment of all TLS sections. |
| 4696 | // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold, |
| 4697 | // in-file offsets have to be aligned against the start of TLS program header. |
| 4698 | // If that's not ensured, then in a multi-threaded context, TLS variables across a shared object |
| 4699 | // boundary may not get correctly loaded at an aligned address. |
| 4700 | const Align = struct { |
| 4701 | tls_start_align: u64 = 1, |
| 4702 | first_tls_index: ?usize = null, |
| 4703 | |
| 4704 | fn isFirstTlsShdr(this: @This(), other: usize) bool { |
| 4705 | if (this.first_tls_index) |index| return index == other; |
| 4706 | return false; |
| 4707 | } |
| 4708 | |
| 4709 | fn @"align"(this: @This(), index: usize, sh_addralign: u64, addr: u64) u64 { |
| 4710 | const alignment = if (this.isFirstTlsShdr(index)) this.tls_start_align else sh_addralign; |
| 4711 | return mem.alignForward(u64, addr, alignment); |
| 4712 | } |
| 4713 | }; |
| 4714 | |
| 4715 | var alignment = Align{}; |
| 4716 | for (self.shdrs.items, 0..) |*shdr, i| { |
| 4717 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4718 | if (!shdrIsTls(shdr)) continue; |
| 4719 | if (alignment.first_tls_index == null) alignment.first_tls_index = i; |
| 4720 | alignment.tls_start_align = @max(alignment.tls_start_align, shdr.sh_addralign); |
| 4721 | } |
| 4722 | |
| 4723 | const gpa = self.base.allocator; |
| 4724 | const nphdrs = self.calcNumberOfSegments(); |
| 4725 | var cuts = try gpa.alloc(struct { start: u16, len: u16 }, nphdrs); |
| 4726 | defer gpa.free(cuts); |
| 4727 | |
| 4728 | var shndx = for (self.shdrs.items, 0..) |shdr, in| { |
| 4729 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4730 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4731 | break @as(u16, @intCast(in)); |
| 4732 | } else @as(u16, @intCast(self.shdrs.items.len)); |
| 4733 | |
| 4734 | for (cuts) |*cut| { |
| 4735 | cut.* = .{ .start = shndx, .len = 0 }; |
| 4736 | var flags = shdrToPhdrFlags(self.shdrs.items[shndx].sh_flags); |
| 4737 | |
| 4738 | while (shndx < self.shdrs.items.len) : (shndx += 1) { |
| 4739 | const shdr = &self.shdrs.items[shndx]; |
| 4740 | if (!shdrIsAlloc(shdr)) break; |
| 4741 | if (shdrToPhdrFlags(shdr.sh_flags) != flags) { |
| 4742 | cut.len = shndx - cut.start; |
| 4743 | break; |
| 4744 | } |
| 4745 | } |
| 4746 | } |
| 4747 | cuts[nphdrs - 1].len = shndx - cuts[nphdrs - 1].start; |
| 4748 | |
| 4749 | // Allocate in segments |
| 4750 | const phdr_table = &self.phdrs.items[self.phdr_table_load_index.?]; |
| 4751 | var addr = phdr_table.p_vaddr + phdr_table.p_memsz; |
| 4752 | |
| 4753 | for (cuts) |cut| { |
| 4754 | const slice = self.shdrs.items[cut.start..][0..cut.len]; |
| 4755 | |
| 4756 | var @"align": u64 = self.page_size; |
| 4757 | for (slice) |*shdr| { |
| 4758 | if (shdrIsTbss(shdr)) continue; |
| 4759 | @"align" = @max(@"align", shdr.sh_addralign); |
| 4760 | } |
| 4761 | |
| 4762 | addr = mem.alignForward(u64, addr, @"align"); |
| 4763 | |
| 4764 | var memsz: u64 = 0; |
| 4765 | var filesz: u64 = 0; |
| 4766 | var i: usize = 0; |
| 4767 | while (i < cut.len) : (i += 1) { |
| 4768 | const shdr = &slice[i]; |
| 4769 | if (shdrIsTbss(shdr)) { |
| 4770 | // .tbss is a little special as it's used only by the loader meaning it doesn't |
| 4771 | // need to be actually mmap'ed at runtime. We still need to correctly increment |
| 4772 | // the addresses of every TLS zerofill section tho. Thus, we hack it so that |
| 4773 | // we increment the start address like normal, however, after we are done, |
| 4774 | // the next ALLOC section will get its start address allocated within the same |
| 4775 | // range as the .tbss sections. We will get something like this: |
| 4776 | // |
| 4777 | // ... |
| 4778 | // .tbss 0x10 |
| 4779 | // .tcommon 0x20 |
| 4780 | // .data 0x10 |
| 4781 | // ... |
| 4782 | var tbss_addr = addr; |
| 4783 | while (i < cut.len and shdrIsTbss(&slice[i])) : (i += 1) { |
| 4784 | const tbss_shdr = &slice[i]; |
| 4785 | tbss_addr = alignment.@"align"(cut.start + i, tbss_shdr.sh_addralign, tbss_addr); |
| 4786 | tbss_shdr.sh_addr = tbss_addr; |
| 4787 | tbss_addr += tbss_shdr.sh_size; |
| 4788 | } |
| 4789 | i -= 1; |
| 4790 | continue; |
| 4791 | } |
| 4792 | const next = alignment.@"align"(cut.start + i, shdr.sh_addralign, addr); |
| 4793 | const padding = next - addr; |
| 4794 | addr = next; |
| 4795 | shdr.sh_addr = addr; |
| 4796 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 4797 | filesz += padding + shdr.sh_size; |
| 4798 | } |
| 4799 | memsz += padding + shdr.sh_size; |
| 4800 | addr += shdr.sh_size; |
| 4801 | } |
| 4802 | |
| 4803 | var off = self.findFreeSpace(filesz, @"align"); |
| 4804 | const phndx = try self.addPhdr(.{ |
| 4805 | .type = elf.PT_LOAD, |
| 4806 | .offset = off, |
| 4807 | .addr = slice[0].sh_addr, |
| 4808 | .memsz = memsz, |
| 4809 | .filesz = filesz, |
| 4810 | .@"align" = @"align", |
| 4811 | .flags = shdrToPhdrFlags(slice[0].sh_flags), |
| 4812 | }); |
| 4813 | |
| 4814 | for (slice, 0..) |*shdr, ii| { |
| 4815 | if (shdrIsZerofill(shdr)) continue; |
| 4816 | off = alignment.@"align"(cut.start + ii, shdr.sh_addralign, off); |
| 4817 | // off = mem.alignForward(u64, off, shdr.sh_addralign); |
| 4818 | shdr.sh_offset = off; |
| 4819 | off += shdr.sh_size; |
| 4820 | try self.phdr_to_shdr_table.putNoClobber(gpa, @intCast(ii + cut.start), phndx); |
| 4821 | } |
| 4822 | |
| 4823 | addr += self.page_size; |
| 4824 | } |
| 4825 | } |
| 4826 | |
| 4674 | 4827 | fn allocateNonAllocSections(self: *Elf) void { |
| 4675 | 4828 | for (self.shdrs.items) |*shdr| { |
| 4676 | 4829 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| ... | ... | @@ -5817,65 +5970,78 @@ fn reportParseError( |
| 5817 | 5970 | try err.addNote(self, "while parsing {s}", .{path}); |
| 5818 | 5971 | } |
| 5819 | 5972 | |
| 5820 | | fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) { |
| 5821 | | return .{ .data = self }; |
| 5973 | const FormatShdrCtx = struct { |
| 5974 | elf_file: *Elf, |
| 5975 | shdr: elf.Elf64_Shdr, |
| 5976 | }; |
| 5977 | |
| 5978 | fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(formatShdr) { |
| 5979 | return .{ .data = .{ |
| 5980 | .shdr = shdr, |
| 5981 | .elf_file = self, |
| 5982 | } }; |
| 5822 | 5983 | } |
| 5823 | 5984 | |
| 5824 | | fn formatShdrs( |
| 5825 | | self: *Elf, |
| 5985 | fn formatShdr( |
| 5986 | ctx: FormatShdrCtx, |
| 5826 | 5987 | comptime unused_fmt_string: []const u8, |
| 5827 | 5988 | options: std.fmt.FormatOptions, |
| 5828 | 5989 | writer: anytype, |
| 5829 | 5990 | ) !void { |
| 5830 | 5991 | _ = options; |
| 5831 | 5992 | _ = unused_fmt_string; |
| 5832 | | for (self.shdrs.items, 0..) |shdr, i| { |
| 5833 | | try writer.print("shdr({d}) : phdr({?d}) : {s} : @{x} ({x}) : align({x}) : size({x})\n", .{ |
| 5834 | | i, self.phdr_to_shdr_table.get(@intCast(i)), |
| 5835 | | self.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset, |
| 5836 | | shdr.sh_addr, shdr.sh_addralign, |
| 5837 | | shdr.sh_size, |
| 5838 | | }); |
| 5839 | | } |
| 5993 | const shdr = ctx.shdr; |
| 5994 | try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{ |
| 5995 | ctx.elf_file.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset, |
| 5996 | shdr.sh_addr, shdr.sh_addralign, |
| 5997 | shdr.sh_size, |
| 5998 | }); |
| 5840 | 5999 | } |
| 5841 | 6000 | |
| 5842 | | fn fmtPhdrs(self: *Elf) std.fmt.Formatter(formatPhdrs) { |
| 5843 | | return .{ .data = self }; |
| 6001 | const FormatPhdrCtx = struct { |
| 6002 | elf_file: *Elf, |
| 6003 | phdr: elf.Elf64_Phdr, |
| 6004 | }; |
| 6005 | |
| 6006 | fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) { |
| 6007 | return .{ .data = .{ |
| 6008 | .phdr = phdr, |
| 6009 | .elf_file = self, |
| 6010 | } }; |
| 5844 | 6011 | } |
| 5845 | 6012 | |
| 5846 | | fn formatPhdrs( |
| 5847 | | self: *Elf, |
| 6013 | fn formatPhdr( |
| 6014 | ctx: FormatPhdrCtx, |
| 5848 | 6015 | comptime unused_fmt_string: []const u8, |
| 5849 | 6016 | options: std.fmt.FormatOptions, |
| 5850 | 6017 | writer: anytype, |
| 5851 | 6018 | ) !void { |
| 5852 | 6019 | _ = options; |
| 5853 | 6020 | _ = unused_fmt_string; |
| 5854 | | for (self.phdrs.items, 0..) |phdr, i| { |
| 5855 | | const write = phdr.p_flags & elf.PF_W != 0; |
| 5856 | | const read = phdr.p_flags & elf.PF_R != 0; |
| 5857 | | const exec = phdr.p_flags & elf.PF_X != 0; |
| 5858 | | var flags: [3]u8 = [_]u8{'_'} ** 3; |
| 5859 | | if (exec) flags[0] = 'X'; |
| 5860 | | if (write) flags[1] = 'W'; |
| 5861 | | if (read) flags[2] = 'R'; |
| 5862 | | const p_type = switch (phdr.p_type) { |
| 5863 | | elf.PT_LOAD => "LOAD", |
| 5864 | | elf.PT_TLS => "TLS", |
| 5865 | | elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME", |
| 5866 | | elf.PT_GNU_STACK => "GNU_STACK", |
| 5867 | | elf.PT_DYNAMIC => "DYNAMIC", |
| 5868 | | elf.PT_INTERP => "INTERP", |
| 5869 | | elf.PT_NULL => "NULL", |
| 5870 | | elf.PT_PHDR => "PHDR", |
| 5871 | | elf.PT_NOTE => "NOTE", |
| 5872 | | else => "UNKNOWN", |
| 5873 | | }; |
| 5874 | | try writer.print("phdr({d}) : {s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{ |
| 5875 | | i, p_type, flags, phdr.p_offset, phdr.p_vaddr, |
| 5876 | | phdr.p_align, phdr.p_filesz, phdr.p_memsz, |
| 5877 | | }); |
| 5878 | | } |
| 6021 | const phdr = ctx.phdr; |
| 6022 | const write = phdr.p_flags & elf.PF_W != 0; |
| 6023 | const read = phdr.p_flags & elf.PF_R != 0; |
| 6024 | const exec = phdr.p_flags & elf.PF_X != 0; |
| 6025 | var flags: [3]u8 = [_]u8{'_'} ** 3; |
| 6026 | if (exec) flags[0] = 'X'; |
| 6027 | if (write) flags[1] = 'W'; |
| 6028 | if (read) flags[2] = 'R'; |
| 6029 | const p_type = switch (phdr.p_type) { |
| 6030 | elf.PT_LOAD => "LOAD", |
| 6031 | elf.PT_TLS => "TLS", |
| 6032 | elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME", |
| 6033 | elf.PT_GNU_STACK => "GNU_STACK", |
| 6034 | elf.PT_DYNAMIC => "DYNAMIC", |
| 6035 | elf.PT_INTERP => "INTERP", |
| 6036 | elf.PT_NULL => "NULL", |
| 6037 | elf.PT_PHDR => "PHDR", |
| 6038 | elf.PT_NOTE => "NOTE", |
| 6039 | else => "UNKNOWN", |
| 6040 | }; |
| 6041 | try writer.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{ |
| 6042 | p_type, flags, phdr.p_offset, phdr.p_vaddr, |
| 6043 | phdr.p_align, phdr.p_filesz, phdr.p_memsz, |
| 6044 | }); |
| 5879 | 6045 | } |
| 5880 | 6046 | |
| 5881 | 6047 | fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { |
| ... | ... | @@ -5928,9 +6094,17 @@ fn fmtDumpState( |
| 5928 | 6094 | } |
| 5929 | 6095 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| 5930 | 6096 | try writer.writeAll("Output shdrs\n"); |
| 5931 | | try writer.print("{}\n", .{self.fmtShdrs()}); |
| 6097 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 6098 | try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{ |
| 6099 | shndx, |
| 6100 | self.phdr_to_shdr_table.get(@intCast(shndx)), |
| 6101 | self.fmtShdr(shdr), |
| 6102 | }); |
| 6103 | } |
| 5932 | 6104 | try writer.writeAll("Output phdrs\n"); |
| 5933 | | try writer.print("{}\n", .{self.fmtPhdrs()}); |
| 6105 | for (self.phdrs.items, 0..) |phdr, phndx| { |
| 6106 | try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) }); |
| 6107 | } |
| 5934 | 6108 | } |
| 5935 | 6109 | |
| 5936 | 6110 | /// Binary search |