authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-25 19:40:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-26 21:07:47+02:00
logeb497c50e331550a2d28d45a77a7558a49a83e7c
treee74ff17c64734d0ea7e6f73792c4f191acbb5238
parent5e617e4b0c35c75e8079f3c0918392327a55d413

elf: dynamically allocate remaining alloc sections (and segments)


2 files changed, 76 insertions(+), 22 deletions(-)

src/link/Elf.zig+40-14
...@@ -409,16 +409,24 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {...@@ -409,16 +409,24 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
409}409}
410410
411const AllocateSegmentOpts = struct {411const AllocateSegmentOpts = struct {
412 addr: u64, // TODO find free VM space
413 size: u64,412 size: u64,
414 alignment: u64,413 alignment: u64,
414 addr: ?u64 = null, // TODO find free VM space
415 flags: u32 = elf.PF_R,415 flags: u32 = elf.PF_R,
416};416};
417417
418fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 {418pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 {
419 const index = @as(u16, @intCast(self.phdrs.items.len));419 const index = @as(u16, @intCast(self.phdrs.items.len));
420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);
421 const off = self.findFreeSpace(opts.size, opts.alignment);421 const off = self.findFreeSpace(opts.size, opts.alignment);
422 // Memory is always allocated in sequence.
423 // TODO is this correct? Or should we implement something similar to `findFreeSpace`?
424 // How would that impact HCS?
425 const addr = opts.addr orelse blk: {
426 assert(self.phdr_table_load_index != null);
427 const phdr = &self.phdrs.items[index - 1];
428 break :blk mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, opts.alignment);
429 };
422 log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{430 log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
423 index,431 index,
424 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',432 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',
...@@ -426,15 +434,15 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16...@@ -426,15 +434,15 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16
426 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',434 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',
427 off,435 off,
428 off + opts.size,436 off + opts.size,
429 opts.addr,437 addr,
430 opts.addr + opts.size,438 addr + opts.size,
431 });439 });
432 self.phdrs.appendAssumeCapacity(.{440 self.phdrs.appendAssumeCapacity(.{
433 .p_type = elf.PT_LOAD,441 .p_type = elf.PT_LOAD,
434 .p_offset = off,442 .p_offset = off,
435 .p_filesz = opts.size,443 .p_filesz = opts.size,
436 .p_vaddr = opts.addr,444 .p_vaddr = addr,
437 .p_paddr = opts.addr,445 .p_paddr = addr,
438 .p_memsz = opts.size,446 .p_memsz = opts.size,
439 .p_align = opts.alignment,447 .p_align = opts.alignment,
440 .p_flags = opts.flags,448 .p_flags = opts.flags,
...@@ -446,12 +454,12 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16...@@ -446,12 +454,12 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16
446const AllocateAllocSectionOpts = struct {454const AllocateAllocSectionOpts = struct {
447 name: [:0]const u8,455 name: [:0]const u8,
448 phdr_index: u16,456 phdr_index: u16,
449 alignment: u16 = 1,457 alignment: u64 = 1,
450 flags: u16 = elf.SHF_ALLOC,458 flags: u64 = elf.SHF_ALLOC,
451 type: u32 = elf.SHT_PROGBITS,459 type: u32 = elf.SHT_PROGBITS,
452};460};
453461
454fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 {462pub fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 {
455 const gpa = self.base.allocator;463 const gpa = self.base.allocator;
456 const phdr = &self.phdrs.items[opts.phdr_index];464 const phdr = &self.phdrs.items[opts.phdr_index];
457 const index = @as(u16, @intCast(self.shdrs.items.len));465 const index = @as(u16, @intCast(self.shdrs.items.len));
...@@ -622,6 +630,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -622,6 +630,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
622 });630 });
623 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];631 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
624 phdr.p_offset = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; // .bss overlaps .data632 phdr.p_offset = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; // .bss overlaps .data
633 phdr.p_memsz = 1024;
625 }634 }
626635
627 if (self.shstrtab_section_index == null) {636 if (self.shstrtab_section_index == null) {
...@@ -994,6 +1003,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -994,6 +1003,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
994 try positionals.append(.{ .path = key.status.success.object_path });1003 try positionals.append(.{ .path = key.status.success.object_path });
995 }1004 }
9961005
1006 // csu prelude
1007 var csu = try CsuObjects.init(arena, self.base.options, comp);
1008 if (csu.crt0) |v| try positionals.append(.{ .path = v });
1009 if (csu.crti) |v| try positionals.append(.{ .path = v });
1010 if (csu.crtbegin) |v| try positionals.append(.{ .path = v });
1011
997 for (positionals.items) |obj| {1012 for (positionals.items) |obj| {
998 const in_file = try std.fs.cwd().openFile(obj.path, .{});1013 const in_file = try std.fs.cwd().openFile(obj.path, .{});
999 defer in_file.close();1014 defer in_file.close();
...@@ -1039,18 +1054,29 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1039,18 +1054,29 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1039 try self.handleAndReportParseError(lib.path, err, &parse_ctx);1054 try self.handleAndReportParseError(lib.path, err, &parse_ctx);
1040 }1055 }
10411056
1042 // Finally, as the last input object add compiler_rt if any.1057 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
1058 positionals.clearRetainingCapacity();
1059
1060 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
1061 // to be after the shared libraries, so they are picked up from the shared
1062 // libraries, not libcompiler_rt.
1043 const compiler_rt_path: ?[]const u8 = blk: {1063 const compiler_rt_path: ?[]const u8 = blk: {
1044 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1064 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1045 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;1065 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
1046 break :blk null;1066 break :blk null;
1047 };1067 };
1048 if (compiler_rt_path) |path| {1068 if (compiler_rt_path) |path| try positionals.append(.{ .path = path });
1049 const in_file = try std.fs.cwd().openFile(path, .{});1069
1070 // csu postlude
1071 if (csu.crtend) |v| try positionals.append(.{ .path = v });
1072 if (csu.crtn) |v| try positionals.append(.{ .path = v });
1073
1074 for (positionals.items) |obj| {
1075 const in_file = try std.fs.cwd().openFile(obj.path, .{});
1050 defer in_file.close();1076 defer in_file.close();
1051 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1077 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1052 self.parsePositional(in_file, path, false, &parse_ctx) catch |err|1078 self.parsePositional(in_file, obj.path, obj.must_link, &parse_ctx) catch |err|
1053 try self.handleAndReportParseError(path, err, &parse_ctx);1079 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1054 }1080 }
10551081
1056 // Handle any lazy symbols that were emitted by incremental compilation.1082 // Handle any lazy symbols that were emitted by incremental compilation.
src/link/Elf/Object.zig+36-8
...@@ -136,7 +136,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -136,7 +136,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
136 try self.comdat_groups.append(elf_file.base.allocator, comdat_group_index);136 try self.comdat_groups.append(elf_file.base.allocator, comdat_group_index);
137 },137 },
138138
139 elf.SHT_SYMTAB_SHNDX => @panic("TODO"),139 elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),
140140
141 elf.SHT_NULL,141 elf.SHT_NULL,
142 elf.SHT_REL,142 elf.SHT_REL,
...@@ -166,14 +166,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -166,14 +166,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
166 };166 };
167}167}
168168
169fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, elf_file: *Elf) !void {169fn addAtom(
170 self: *Object,
171 shdr: elf.Elf64_Shdr,
172 shndx: u16,
173 name: [:0]const u8,
174 elf_file: *Elf,
175) error{ OutOfMemory, Overflow }!void {
170 const atom_index = try elf_file.addAtom();176 const atom_index = try elf_file.addAtom();
171 const atom = elf_file.atom(atom_index).?;177 const atom = elf_file.atom(atom_index).?;
172 atom.atom_index = atom_index;178 atom.atom_index = atom_index;
173 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);179 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);
174 atom.file_index = self.index;180 atom.file_index = self.index;
175 atom.input_section_index = shndx;181 atom.input_section_index = shndx;
176 atom.output_section_index = self.getOutputSectionIndex(elf_file, shdr);182 atom.output_section_index = try self.getOutputSectionIndex(elf_file, shdr);
177 atom.alive = true;183 atom.alive = true;
178 self.atoms.items[shndx] = atom_index;184 self.atoms.items[shndx] = atom_index;
179185
...@@ -188,7 +194,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,...@@ -188,7 +194,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,
188 }194 }
189}195}
190196
191fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) u16 {197fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
192 const name = blk: {198 const name = blk: {
193 const name = self.strings.getAssumeExists(shdr.sh_name);199 const name = self.strings.getAssumeExists(shdr.sh_name);
194 // if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;200 // if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
...@@ -223,10 +229,32 @@ fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) u1...@@ -223,10 +229,32 @@ fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) u1
223 else => flags,229 else => flags,
224 };230 };
225 };231 };
226 _ = flags;232 const out_shndx = elf_file.sectionByName(name) orelse blk: {
227 const out_shndx = elf_file.sectionByName(name) orelse {233 const is_alloc = flags & elf.SHF_ALLOC != 0;
228 log.err("{}: output section {s} not found", .{ self.fmtPath(), name });234 const is_write = flags & elf.SHF_WRITE != 0;
229 @panic("TODO: missing output section!");235 const is_exec = flags & elf.SHF_EXECINSTR != 0;
236 const is_tls = flags & elf.SHF_TLS != 0;
237 if (!is_alloc or is_tls) {
238 log.err("{}: output section {s} not found", .{ self.fmtPath(), name });
239 @panic("TODO: missing output section!");
240 }
241 var phdr_flags: u32 = elf.PF_R;
242 if (is_write) phdr_flags |= elf.PF_W;
243 if (is_exec) phdr_flags |= elf.PF_X;
244 const phdr_index = try elf_file.allocateSegment(.{
245 .size = Elf.padToIdeal(shdr.sh_size),
246 .alignment = if (is_tls) shdr.sh_addralign else elf_file.page_size,
247 .flags = phdr_flags,
248 });
249 const shndx = try elf_file.allocateAllocSection(.{
250 .name = name,
251 .phdr_index = phdr_index,
252 .alignment = shdr.sh_addralign,
253 .flags = flags,
254 .type = @"type",
255 });
256 try elf_file.last_atom_and_free_list_table.putNoClobber(elf_file.base.allocator, shndx, .{});
257 break :blk shndx;
230 };258 };
231 return out_shndx;259 return out_shndx;
232}260}