diff options
| author | Xavier Bouchoux <xavierb@gmail.com> | 2023-03-12 11:08:06 +0100 |
|---|---|---|
| committer | Xavier Bouchoux <xavierb@gmail.com> | 2023-03-20 08:39:23 +0100 |
| commit | b014ffc74f5c2c497ef62e1f77132287288f8bba (patch) | |
| tree | 85dbfd9884c2f28c9db821922941fd5d87d0b877 /src | |
| parent | 7ab48163eee3288444f664fd709d74e4148832a3 (diff) | |
| download | zig-b014ffc74f5c2c497ef62e1f77132287288f8bba.tar.gz zig-b014ffc74f5c2c497ef62e1f77132287288f8bba.zip | |
objcopy: use defined data for padding ELF sections
Seems the right thing to do, but not strictly necessary.
Diffstat (limited to 'src')
| -rw-r--r-- | src/objcopy.zig | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/src/objcopy.zig b/src/objcopy.zig index dfd506a74a..35bc0d29a5 100644 --- a/src/objcopy.zig +++ b/src/objcopy.zig @@ -924,7 +924,7 @@ const ElfContents = struct { // - unused sections are removed // when emitting the debug file: // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS - // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works) TODO: maybe it can be omitted altogether from debug? + // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works) const Update = struct { action: enum { keep, strip, empty }, @@ -1021,6 +1021,7 @@ const ElfContents = struct { eof_offset = @sizeOf(elf.Elf64_Ehdr); // program header as-is. + // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation. { std.debug.assert(updated_elf_header.e_phoff == @sizeOf(elf.Elf64_Ehdr)); const data = std.mem.sliceAsBytes(self.program_segments); @@ -1164,10 +1165,60 @@ const ElfContents = struct { cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } }); } - // write the target files - // TODO: pack together contiguous copies (cmdbuf is ordered, by construction) - // TODO: fill the paddings with zero or copy from source file - for (cmdbuf.items) |cmd| { + // consolidate holes between writes: + // by coping original padding data from in_file (by fusing contiguous ranges) + // by writing zeroes otherwise + const zeroes = [1]u8{0} ** 4096; + const consolidated_cmdbuf = blk: { + var newbuf = std.ArrayList(WriteCmd).init(allocator); + try newbuf.ensureUnusedCapacity(cmdbuf.items.len * 2); + var offset: u64 = 0; + var fused_cmd: ?WriteCmd = null; + for (cmdbuf.items) |cmd| { + switch (cmd) { + .write_data => |data| { + std.debug.assert(data.out_offset >= offset); + if (fused_cmd) |prev| { + newbuf.appendAssumeCapacity(prev); + fused_cmd = null; + } + if (data.out_offset > offset) { + newbuf.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0 .. @intCast(usize, data.out_offset - offset)], .out_offset = offset } }); + } + newbuf.appendAssumeCapacity(cmd); + offset = data.out_offset + data.data.len; + }, + .copy_range => |range| { + std.debug.assert(range.out_offset >= offset); + if (fused_cmd) |prev| { + if (range.in_offset >= prev.copy_range.in_offset + prev.copy_range.len and (range.out_offset - prev.copy_range.out_offset == range.in_offset - prev.copy_range.in_offset)) { + fused_cmd = .{ .copy_range = .{ + .in_offset = prev.copy_range.in_offset, + .out_offset = prev.copy_range.out_offset, + .len = (range.out_offset + range.len) - prev.copy_range.out_offset, + } }; + } else { + newbuf.appendAssumeCapacity(prev); + if (range.out_offset > offset) { + newbuf.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0 .. @intCast(usize, range.out_offset - offset)], .out_offset = offset } }); + } + fused_cmd = cmd; + } + } else { + fused_cmd = cmd; + } + offset = range.out_offset + range.len; + }, + } + } + if (fused_cmd) |cmd| { + newbuf.appendAssumeCapacity(cmd); + } + break :blk newbuf.items; + }; + + // write the output file + for (consolidated_cmdbuf) |cmd| { switch (cmd) { .write_data => |data| { var iovec = [_]std.os.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }}; |
