authorgravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-03-12 11:08:06+01:00
committergravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-03-20 08:39:23+01:00
logb014ffc74f5c2c497ef62e1f77132287288f8bba
tree85dbfd9884c2f28c9db821922941fd5d87d0b877
parent7ab48163eee3288444f664fd709d74e4148832a3

objcopy: use defined data for padding ELF sections

Seems the right thing to do, but not strictly necessary.

1 files changed, 56 insertions(+), 5 deletions(-)

src/objcopy.zig+56-5
...@@ -924,7 +924,7 @@ const ElfContents = struct {...@@ -924,7 +924,7 @@ const ElfContents = struct {
924 // - unused sections are removed924 // - unused sections are removed
925 // when emitting the debug file:925 // when emitting the debug file:
926 // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS926 // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS
927 // 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?927 // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works)
928928
929 const Update = struct {929 const Update = struct {
930 action: enum { keep, strip, empty },930 action: enum { keep, strip, empty },
...@@ -1021,6 +1021,7 @@ const ElfContents = struct {...@@ -1021,6 +1021,7 @@ const ElfContents = struct {
1021 eof_offset = @sizeOf(elf.Elf64_Ehdr);1021 eof_offset = @sizeOf(elf.Elf64_Ehdr);
10221022
1023 // program header as-is.1023 // program header as-is.
1024 // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation.
1024 {1025 {
1025 std.debug.assert(updated_elf_header.e_phoff == @sizeOf(elf.Elf64_Ehdr));1026 std.debug.assert(updated_elf_header.e_phoff == @sizeOf(elf.Elf64_Ehdr));
1026 const data = std.mem.sliceAsBytes(self.program_segments);1027 const data = std.mem.sliceAsBytes(self.program_segments);
...@@ -1164,10 +1165,60 @@ const ElfContents = struct {...@@ -1164,10 +1165,60 @@ const ElfContents = struct {
1164 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } });1165 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } });
1165 }1166 }
11661167
1167 // write the target files1168 // consolidate holes between writes:
1168 // TODO: pack together contiguous copies (cmdbuf is ordered, by construction)1169 // by coping original padding data from in_file (by fusing contiguous ranges)
1169 // TODO: fill the paddings with zero or copy from source file1170 // by writing zeroes otherwise
1170 for (cmdbuf.items) |cmd| {1171 const zeroes = [1]u8{0} ** 4096;
1172 const consolidated_cmdbuf = blk: {
1173 var newbuf = std.ArrayList(WriteCmd).init(allocator);
1174 try newbuf.ensureUnusedCapacity(cmdbuf.items.len * 2);
1175 var offset: u64 = 0;
1176 var fused_cmd: ?WriteCmd = null;
1177 for (cmdbuf.items) |cmd| {
1178 switch (cmd) {
1179 .write_data => |data| {
1180 std.debug.assert(data.out_offset >= offset);
1181 if (fused_cmd) |prev| {
1182 newbuf.appendAssumeCapacity(prev);
1183 fused_cmd = null;
1184 }
1185 if (data.out_offset > offset) {
1186 newbuf.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0 .. @intCast(usize, data.out_offset - offset)], .out_offset = offset } });
1187 }
1188 newbuf.appendAssumeCapacity(cmd);
1189 offset = data.out_offset + data.data.len;
1190 },
1191 .copy_range => |range| {
1192 std.debug.assert(range.out_offset >= offset);
1193 if (fused_cmd) |prev| {
1194 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)) {
1195 fused_cmd = .{ .copy_range = .{
1196 .in_offset = prev.copy_range.in_offset,
1197 .out_offset = prev.copy_range.out_offset,
1198 .len = (range.out_offset + range.len) - prev.copy_range.out_offset,
1199 } };
1200 } else {
1201 newbuf.appendAssumeCapacity(prev);
1202 if (range.out_offset > offset) {
1203 newbuf.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0 .. @intCast(usize, range.out_offset - offset)], .out_offset = offset } });
1204 }
1205 fused_cmd = cmd;
1206 }
1207 } else {
1208 fused_cmd = cmd;
1209 }
1210 offset = range.out_offset + range.len;
1211 },
1212 }
1213 }
1214 if (fused_cmd) |cmd| {
1215 newbuf.appendAssumeCapacity(cmd);
1216 }
1217 break :blk newbuf.items;
1218 };
1219
1220 // write the output file
1221 for (consolidated_cmdbuf) |cmd| {
1171 switch (cmd) {1222 switch (cmd) {
1172 .write_data => |data| {1223 .write_data => |data| {
1173 var iovec = [_]std.os.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }};1224 var iovec = [_]std.os.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }};