authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-02 11:42:47+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:34:26+02:00
log5cb51c10debd3e9542e35e22648bca2a8b59259e
tree94cb57d962197ebd93d055fb9591a459126983e0
parent6b53dc946117110907867ee67425585ae3729750

elf: fix relocatable mode


5 files changed, 67 insertions(+), 117 deletions(-)

src/link/Elf.zig+9-23
......@@ -3577,29 +3577,15 @@ fn updateSectionSizes(self: *Elf) !void {
35773577 }
35783578
35793579 const slice = self.sections.slice();
3580 // for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
3581 // if (atom_list.items.len == 0) continue;
3582 // if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
3583 // for (atom_list.items) |ref| {
3584 // const atom_ptr = self.atom(ref) orelse continue;
3585 // if (!atom_ptr.alive) continue;
3586 // const offset = atom_ptr.alignment.forward(shdr.sh_size);
3587 // const padding = offset - shdr.sh_size;
3588 // atom_ptr.value = @intCast(offset);
3589 // shdr.sh_size += padding + atom_ptr.size;
3590 // shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
3591 // }
3592 // }
3593
3594 // if (self.requiresThunks()) {
3595 // for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| {
3596 // if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
3597 // if (atom_list.items.len == 0) continue;
3598
3599 // // Create jump/branch range extenders if needed.
3600 // try self.createThunks(shdr, @intCast(shndx));
3601 // }
3602 // }
3580 if (self.requiresThunks()) {
3581 for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| {
3582 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
3583 if (atom_list.items.len == 0) continue;
3584
3585 // Create jump/branch range extenders if needed.
3586 try self.createThunks(shdr, @intCast(shndx));
3587 }
3588 }
36033589
36043590 const shdrs = slice.items(.shdr);
36053591 if (self.eh_frame_section_index) |index| {
src/link/Elf/Object.zig+38-1
......@@ -575,7 +575,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
575575 }
576576}
577577
578pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
578pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void {
579579 const first_global = self.first_global orelse return;
580580 for (self.globals(), 0..) |*sym, i| {
581581 const esym_index = @as(u32, @intCast(first_global + i));
......@@ -1046,6 +1046,43 @@ pub fn writeAtoms(self: *Object, elf_file: *Elf) !void {
10461046 if (has_reloc_errors) return error.FlushFailure;
10471047}
10481048
1049pub fn writeAtomsRelocatable(self: *Object, elf_file: *Elf) !void {
1050 const gpa = elf_file.base.comp.gpa;
1051
1052 var buffer = std.ArrayList(u8).init(gpa);
1053 defer buffer.deinit();
1054
1055 log.debug("writing atoms in {}", .{self.fmtPath()});
1056
1057 for (self.section_chunks.items) |chunk| {
1058 const osec = elf_file.sections.items(.shdr)[chunk.output_section_index];
1059 if (osec.sh_type == elf.SHT_NOBITS) continue;
1060
1061 log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)});
1062
1063 try buffer.ensureUnusedCapacity(chunk.size);
1064 buffer.appendNTimesAssumeCapacity(0, chunk.size);
1065
1066 for (chunk.atoms.items) |atom_index| {
1067 const atom_ptr = self.atom(atom_index).?;
1068 assert(atom_ptr.alive);
1069
1070 const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow;
1071 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1072
1073 log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset });
1074
1075 const code = try self.codeDecompressAlloc(elf_file, atom_index);
1076 defer gpa.free(code);
1077 const out_code = buffer.items[offset..][0..size];
1078 @memcpy(out_code, code);
1079 }
1080
1081 try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file));
1082 buffer.clearRetainingCapacity();
1083 }
1084}
1085
10491086pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
10501087 for (self.atoms_indexes.items) |atom_index| {
10511088 const atom_ptr = self.atom(atom_index) orelse continue;
src/link/Elf/ZigObject.zig+1-1
......@@ -648,7 +648,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
648648 }
649649}
650650
651pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
651pub fn claimUnresolvedRelocatable(self: ZigObject, elf_file: *Elf) void {
652652 for (self.global_symbols.items, 0..) |index, i| {
653653 const global = &self.symbols.items[index];
654654 const esym = self.symtab.items(.elf_sym)[index];
src/link/Elf/eh_frame.zig+1-1
......@@ -386,7 +386,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
386386 if (has_reloc_errors) return error.RelocFailure;
387387}
388388
389pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
389pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
390390 for (elf_file.objects.items) |index| {
391391 const object = elf_file.file(index).?.object;
392392
src/link/Elf/relocatable.zig+18-91
......@@ -40,7 +40,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
4040 try zig_object.resolveSymbols(elf_file);
4141 try elf_file.addCommentString();
4242 try elf_file.finalizeMergeSections();
43 zig_object.claimUnresolvedObject(elf_file);
43 zig_object.claimUnresolvedRelocatable(elf_file);
4444
4545 for (elf_file.merge_sections.items) |*msec| {
4646 if (msec.finalized_subsections.items.len == 0) continue;
......@@ -280,10 +280,10 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
280280
281281fn claimUnresolved(elf_file: *Elf) void {
282282 if (elf_file.zigObjectPtr()) |zig_object| {
283 zig_object.claimUnresolvedObject(elf_file);
283 zig_object.claimUnresolvedRelocatable(elf_file);
284284 }
285285 for (elf_file.objects.items) |index| {
286 elf_file.file(index).?.object.claimUnresolvedObject(elf_file);
286 elf_file.file(index).?.object.claimUnresolvedRelocatable(elf_file);
287287 }
288288}
289289
......@@ -349,29 +349,22 @@ fn initComdatGroups(elf_file: *Elf) !void {
349349}
350350
351351fn updateSectionSizes(elf_file: *Elf) !void {
352 for (elf_file.objects.items) |index| {
353 try elf_file.file(index).?.object.allocateAtoms(elf_file);
354 }
355
352356 const slice = elf_file.sections.slice();
353357 for (slice.items(.shdr), 0..) |*shdr, shndx| {
354358 const atom_list = slice.items(.atom_list)[shndx];
355 if (shdr.sh_type != elf.SHT_RELA) {
356 for (atom_list.items) |ref| {
357 const atom_ptr = elf_file.atom(ref) orelse continue;
358 if (!atom_ptr.alive) continue;
359 const offset = atom_ptr.alignment.forward(shdr.sh_size);
360 const padding = offset - shdr.sh_size;
361 atom_ptr.value = @intCast(offset);
362 shdr.sh_size += padding + atom_ptr.size;
363 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
364 }
365 } else {
366 for (atom_list.items) |ref| {
367 const atom_ptr = elf_file.atom(ref) orelse continue;
368 if (!atom_ptr.alive) continue;
369 const relocs = atom_ptr.relocs(elf_file);
370 shdr.sh_size += shdr.sh_entsize * relocs.len;
371 }
372
373 if (shdr.sh_size == 0) shdr.sh_offset = 0;
359 if (shdr.sh_type != elf.SHT_RELA) continue;
360 for (atom_list.items) |ref| {
361 const atom_ptr = elf_file.atom(ref) orelse continue;
362 if (!atom_ptr.alive) continue;
363 const relocs = atom_ptr.relocs(elf_file);
364 shdr.sh_size += shdr.sh_entsize * relocs.len;
374365 }
366
367 if (shdr.sh_size == 0) shdr.sh_offset = 0;
375368 }
376369
377370 if (elf_file.eh_frame_section_index) |index| {
......@@ -422,74 +415,8 @@ fn allocateAllocSections(elf_file: *Elf) !void {
422415}
423416
424417fn writeAtoms(elf_file: *Elf) !void {
425 const gpa = elf_file.base.comp.gpa;
426 const slice = elf_file.sections.slice();
427
428 // TODO iterate over `output_sections` directly
429 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {
430 if (shdr.sh_type == elf.SHT_NULL) continue;
431 if (shdr.sh_type == elf.SHT_NOBITS) continue;
432 if (shdr.sh_type == elf.SHT_RELA) continue;
433 if (atom_list.items.len == 0) continue;
434
435 log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)});
436
437 // TODO really, really handle debug section separately
438 const base_offset = if (elf_file.zigObjectPtr()) |zo| blk: {
439 break :blk for ([_]?Symbol.Index{
440 zo.debug_info_index,
441 zo.debug_abbrev_index,
442 zo.debug_aranges_index,
443 zo.debug_str_index,
444 zo.debug_line_index,
445 zo.debug_line_str_index,
446 zo.debug_loclists_index,
447 zo.debug_rnglists_index,
448 }) |maybe_sym_index| {
449 const sym_index = maybe_sym_index orelse continue;
450 const sym = zo.symbol(sym_index);
451 const atom_ptr = sym.atom(elf_file).?;
452 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
453 } else 0;
454 } else 0;
455 const sh_offset = shdr.sh_offset + base_offset;
456 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
457
458 const buffer = try gpa.alloc(u8, sh_size);
459 defer gpa.free(buffer);
460 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
461 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
462 0xcc // int3
463 else
464 0;
465 @memset(buffer, padding_byte);
466
467 for (atom_list.items) |ref| {
468 const atom_ptr = elf_file.atom(ref).?;
469 assert(atom_ptr.alive);
470
471 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
472 return error.Overflow;
473 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
474
475 log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
476 ref,
477 sh_offset + offset,
478 sh_offset + offset + size,
479 });
480
481 // TODO decompress directly into provided buffer
482 const out_code = buffer[offset..][0..size];
483 const in_code = switch (atom_ptr.file(elf_file).?) {
484 .object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
485 .zig_object => |x| try x.codeAlloc(elf_file, ref.index),
486 else => unreachable,
487 };
488 defer gpa.free(in_code);
489 @memcpy(out_code, in_code);
490 }
491
492 try elf_file.base.file.?.pwriteAll(buffer, sh_offset);
418 for (elf_file.objects.items) |index| {
419 try elf_file.file(index).?.object.writeAtomsRelocatable(elf_file);
493420 }
494421}
495422
......@@ -541,7 +468,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
541468 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
542469 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
543470 defer buffer.deinit();
544 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());
471 try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer());
545472 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
546473 shdr.sh_offset + existing_size,
547474 shdr.sh_offset + sh_size,