diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-09-22 23:17:06 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-09-23 17:14:27 +0200 |
| commit | 9f05cb318b77c18c312592cba52c782d70f2432f (patch) | |
| tree | 641b2ec534bb9047e2ff88973b7e3d8171811971 /src | |
| parent | d9c5a26cfb992b0951c80b80298dba2d690c7639 (diff) | |
| download | zig-9f05cb318b77c18c312592cba52c782d70f2432f.tar.gz zig-9f05cb318b77c18c312592cba52c782d70f2432f.zip | |
elf: put logic for allocating load segments in a helper
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 157 |
1 files changed, 70 insertions, 87 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c850f81ec6..9ab38625e6 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -400,7 +400,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 { return min_pos - start; } -fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { +fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { var start: u64 = 0; while (self.detectAllocCollision(start, object_size)) |item_end| { start = mem.alignForward(u64, item_end, min_alignment); @@ -408,6 +408,38 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { return start; } +const AllocateSegmentOpts = struct { + addr: u64, // TODO find free VM space + size: u64, + alignment: u64, + flags: u32 = elf.PF_R, +}; + +fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) !u16 { + const index = @as(u16, @intCast(self.phdrs.items.len)); + try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1); + const off = self.findFreeSpace(opts.size, opts.alignment); + log.debug("found PHDR {c}{c}{c} free space 0x{x} to 0x{x}", .{ + if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_', + if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_', + if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_', + off, + off + opts.size, + }); + self.phdrs.appendAssumeCapacity(.{ + .p_type = elf.PT_LOAD, + .p_offset = off, + .p_filesz = opts.size, + .p_vaddr = opts.addr, + .p_paddr = opts.addr, + .p_memsz = opts.size, + .p_align = opts.alignment, + .p_flags = opts.flags, + }); + self.phdr_table_dirty = true; + return index; +} + pub fn populateMissingMetadata(self: *Elf) !void { const gpa = self.base.allocator; const small_ptr = switch (self.ptr_width) { @@ -438,7 +470,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { if (self.phdr_table_load_index == null) { self.phdr_table_load_index = @intCast(self.phdrs.items.len); - // TODO Same as for GOT try self.phdrs.append(gpa, .{ .p_type = elf.PT_LOAD, .p_offset = 0, @@ -453,115 +484,67 @@ pub fn populateMissingMetadata(self: *Elf) !void { } if (self.phdr_load_re_index == null) { - self.phdr_load_re_index = @intCast(self.phdrs.items.len); - const file_size = self.base.options.program_code_size_hint; - const p_align = self.page_size; - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size }); - const entry_addr = self.defaultEntryAddress(); - try self.phdrs.append(gpa, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = entry_addr, - .p_paddr = entry_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_X | elf.PF_R | elf.PF_W, + self.phdr_load_re_index = try self.allocateSegment(.{ + .addr = self.defaultEntryAddress(), + .size = self.base.options.program_code_size_hint, + .alignment = self.page_size, + .flags = elf.PF_X | elf.PF_R | elf.PF_W, }); self.entry_addr = null; - self.phdr_table_dirty = true; } if (self.phdr_got_index == null) { - self.phdr_got_index = @intCast(self.phdrs.items.len); - const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; - // We really only need ptr alignment but since we are using PROGBITS, linux requires - // page align. - const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size }); // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. // we'll need to re-use that function anyway, in case the GOT grows and overlaps something // else in virtual memory. - const got_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000; - try self.phdrs.append(gpa, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = got_addr, - .p_paddr = got_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_R | elf.PF_W, + const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000; + // We really only need ptr alignment but since we are using PROGBITS, linux requires + // page align. + const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); + self.phdr_got_index = try self.allocateSegment(.{ + .addr = addr, + .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, + .alignment = alignment, + .flags = elf.PF_R | elf.PF_W, }); - self.phdr_table_dirty = true; } if (self.phdr_load_ro_index == null) { - self.phdr_load_ro_index = @intCast(self.phdrs.items.len); - // TODO Find a hint about how much data need to be in rodata ? - const file_size = 1024; - // Same reason as for GOT - const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size }); // TODO Same as for GOT - const rodata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; - try self.phdrs.append(gpa, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = rodata_addr, - .p_paddr = rodata_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_R | elf.PF_W, + const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; + // Same reason as for GOT + const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); + self.phdr_load_ro_index = try self.allocateSegment(.{ + .addr = addr, + .size = 1024, + .alignment = alignment, + .flags = elf.PF_R | elf.PF_W, }); - self.phdr_table_dirty = true; } if (self.phdr_load_rw_index == null) { - self.phdr_load_rw_index = @intCast(self.phdrs.items.len); - // TODO Find a hint about how much data need to be in data ? - const file_size = 1024; - // Same reason as for GOT - const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size }); // TODO Same as for GOT - const rwdata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; - try self.phdrs.append(gpa, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = rwdata_addr, - .p_paddr = rwdata_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_R | elf.PF_W, + const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; + // Same reason as for GOT + const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); + self.phdr_load_rw_index = try self.allocateSegment(.{ + .addr = addr, + .size = 1024, + .alignment = alignment, + .flags = elf.PF_R | elf.PF_W, }); - self.phdr_table_dirty = true; } if (self.phdr_load_zerofill_index == null) { - self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len); - const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); - const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; - log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); // TODO Same as for GOT - const addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; - try self.phdrs.append(gpa, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = 0, - .p_vaddr = addr, - .p_paddr = addr, - .p_memsz = 0, - .p_align = p_align, - .p_flags = elf.PF_R | elf.PF_W, + const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; + const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); + self.phdr_load_zerofill_index = try self.allocateSegment(.{ + .addr = addr, + .size = 0, + .alignment = alignment, + .flags = elf.PF_R | elf.PF_W, }); - self.phdr_table_dirty = true; } if (self.shstrtab_section_index == null) { |
