authorgravatar for 35903594+patrickwick@users.noreply.github.comPatrick Wickenhaeuser <35903594+patrickwick@users.noreply.github.com> 2024-10-04 12:38:34+02:00
committergravatar for 35903594+patrickwick@users.noreply.github.comPatrick Wickenhaeuser <35903594+patrickwick@users.noreply.github.com> 2024-10-04 15:49:50+02:00
logf72961ee306408cdd3ee4ef5a8bc5301f94fc7e5
tree594719d43bef37d503ea8ab70e5499630ccd9a9c
parent172e7161a48658942c1428963448a68fa07467fa

19009: add --set-section-alignment and --set-section-flags arguments to zig objcopy


1 files changed, 92 insertions(+), 22 deletions(-)

lib/compiler/objcopy.zig+92-22
...@@ -41,6 +41,8 @@ fn cmdObjCopy(...@@ -41,6 +41,8 @@ fn cmdObjCopy(
41 var compress_debug_sections: bool = false;41 var compress_debug_sections: bool = false;
42 var listen = false;42 var listen = false;
43 var add_section: ?AddSectionOptions = null;43 var add_section: ?AddSectionOptions = null;
44 var set_section_alignment: ?SectionAlignmentOptions = null;
45 var set_section_flags: ?SectionFlagsOptions = null;
44 while (i < args.len) : (i += 1) {46 while (i < args.len) : (i += 1) {
45 const arg = args[i];47 const arg = args[i];
46 if (!mem.startsWith(u8, arg, "-")) {48 if (!mem.startsWith(u8, arg, "-")) {
...@@ -105,12 +107,34 @@ fn cmdObjCopy(...@@ -105,12 +107,34 @@ fn cmdObjCopy(
105 i += 1;107 i += 1;
106 if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});108 if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
107 opt_extract = args[i];109 opt_extract = args[i];
110 } else if (mem.eql(u8, arg, "--set-section-alignment")) {
111 i += 1;
112 if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg});
113
114 if (splitOption(args[i])) |split| {
115 const alignment = std.fmt.parseInt(u32, split.second, 10) catch |err| {
116 fatal("unable to parse alignment number: '{s}': {s}", .{ split.second, @errorName(err) });
117 };
118 if (!std.math.isPowerOfTwo(alignment)) fatal("alignment must be a power of two", .{});
119 set_section_alignment = .{ .section_name = split.first, .alignment = alignment };
120 } else {
121 fatal("unrecognized argument: '{s}', expecting <name>=<alignment>", .{args[i]});
122 }
123 } else if (mem.eql(u8, arg, "--set-section-flags")) {
124 i += 1;
125 if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
126
127 if (splitOption(args[i])) |split| {
128 set_section_flags = .{ .section_name = split.first, .flags = split.second };
129 } else {
130 fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]});
131 }
108 } else if (mem.eql(u8, arg, "--add-section")) {132 } else if (mem.eql(u8, arg, "--add-section")) {
109 i += 1;133 i += 1;
110 if (i >= args.len) fatal("expected name and filename arguments after '{s}'", .{arg});134 if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
111135
112 if (splitOption(args[i])) |split| {136 if (splitOption(args[i])) |split| {
113 add_section = .{ .section_name = split.first, .file = split.second };137 add_section = .{ .section_name = split.first, .file_path = split.second };
114 } else {138 } else {
115 fatal("unrecognized argument: '{s}', expecting <name>=<file>", .{args[i]});139 fatal("unrecognized argument: '{s}', expecting <name>=<file>", .{args[i]});
116 }140 }
...@@ -167,6 +191,8 @@ fn cmdObjCopy(...@@ -167,6 +191,8 @@ fn cmdObjCopy(
167 .only_section = only_section,191 .only_section = only_section,
168 .pad_to = pad_to,192 .pad_to = pad_to,
169 .add_section = add_section,193 .add_section = add_section,
194 .set_section_alignment = set_section_alignment,
195 .set_section_flags = set_section_flags,
170 });196 });
171 },197 },
172 .elf => {198 .elf => {
...@@ -187,6 +213,8 @@ fn cmdObjCopy(...@@ -187,6 +213,8 @@ fn cmdObjCopy(
187 .extract_to = opt_extract,213 .extract_to = opt_extract,
188 .compress_debug = compress_debug_sections,214 .compress_debug = compress_debug_sections,
189 .add_section = add_section,215 .add_section = add_section,
216 .set_section_alignment = set_section_alignment,
217 .set_section_flags = set_section_flags,
190 });218 });
191 return std.process.cleanExit();219 return std.process.cleanExit();
192 },220 },
...@@ -229,19 +257,21 @@ const usage =...@@ -229,19 +257,21 @@ const usage =
229 \\Usage: zig objcopy [options] input output257 \\Usage: zig objcopy [options] input output
230 \\258 \\
231 \\Options:259 \\Options:
232 \\ -h, --help Print this help and exit260 \\ -h, --help Print this help and exit
233 \\ --output-target=<value> Format of the output file261 \\ --output-target=<value> Format of the output file
234 \\ -O <value> Alias for --output-target262 \\ -O <value> Alias for --output-target
235 \\ --only-section=<section> Remove all but <section>263 \\ --only-section=<section> Remove all but <section>
236 \\ -j <value> Alias for --only-section264 \\ -j <value> Alias for --only-section
237 \\ --pad-to <addr> Pad the last section up to address <addr>265 \\ --pad-to <addr> Pad the last section up to address <addr>
238 \\ --strip-debug, -g Remove all debug sections from the output.266 \\ --strip-debug, -g Remove all debug sections from the output.
239 \\ --strip-all, -S Remove all debug sections and symbol table from the output.267 \\ --strip-all, -S Remove all debug sections and symbol table from the output.
240 \\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.268 \\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.
241 \\ --add-gnu-debuglink=<file> Creates a .gnu_debuglink section which contains a reference to <file> and adds it to the output file.269 \\ --add-gnu-debuglink=<file> Creates a .gnu_debuglink section which contains a reference to <file> and adds it to the output file.
242 \\ --extract-to <file> Extract the removed sections into <file>, and add a .gnu-debuglink section.270 \\ --extract-to <file> Extract the removed sections into <file>, and add a .gnu-debuglink section.
243 \\ --compress-debug-sections Compress DWARF debug sections with zlib271 \\ --compress-debug-sections Compress DWARF debug sections with zlib
244 \\ --add-section <name>=<file> Add file content from <file> with the section name <name>.272 \\ --set-section-alignment <name>=<align> Set alignment of section <name> to <align> bytes. Must be a power of two.
273 \\ --set-section-flags <name>=<file> Set flags of section <name> to <flags> represented as a comma separated set of flags.
274 \\ --add-section <name>=<file> Add file content from <file> with the section name <name>.
245 \\275 \\
246;276;
247277
...@@ -250,11 +280,25 @@ pub const EmitRawElfOptions = struct {...@@ -250,11 +280,25 @@ pub const EmitRawElfOptions = struct {
250 only_section: ?[]const u8 = null,280 only_section: ?[]const u8 = null,
251 pad_to: ?u64 = null,281 pad_to: ?u64 = null,
252 add_section: ?AddSectionOptions,282 add_section: ?AddSectionOptions,
283 set_section_alignment: ?SectionAlignmentOptions,
284 set_section_flags: ?SectionFlagsOptions,
253};285};
254286
255const AddSectionOptions = struct {287const AddSectionOptions = struct {
256 section_name: []const u8,288 section_name: []const u8,
257 file: []const u8,289 // file to store in new section
290 file_path: []const u8,
291};
292
293const SectionAlignmentOptions = struct {
294 section_name: []const u8,
295 alignment: u32,
296};
297
298const SectionFlagsOptions = struct {
299 section_name: []const u8,
300 // comma separated string representation of the SHF_x flags for Shdr.sh_flags
301 flags: []const u8,
258};302};
259303
260fn emitElf(304fn emitElf(
...@@ -698,6 +742,8 @@ const StripElfOptions = struct {...@@ -698,6 +742,8 @@ const StripElfOptions = struct {
698 only_keep_debug: bool = false,742 only_keep_debug: bool = false,
699 compress_debug: bool = false,743 compress_debug: bool = false,
700 add_section: ?AddSectionOptions,744 add_section: ?AddSectionOptions,
745 set_section_alignment: ?SectionAlignmentOptions,
746 set_section_flags: ?SectionFlagsOptions,
701};747};
702748
703fn stripElf(749fn stripElf(
...@@ -761,7 +807,14 @@ fn stripElf(...@@ -761,7 +807,14 @@ fn stripElf(
761 }807 }
762808
763 const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null;809 const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null;
764 try elf_file.emit(allocator, out_file, in_file, .{ .section_filter = filter, .debuglink = debuglink, .compress_debug = options.compress_debug, .add_section = options.add_section });810 try elf_file.emit(allocator, out_file, in_file, .{
811 .section_filter = filter,
812 .debuglink = debuglink,
813 .compress_debug = options.compress_debug,
814 .add_section = options.add_section,
815 .set_section_alignment = options.set_section_alignment,
816 .set_section_flags = options.set_section_flags,
817 });
765 },818 },
766 }819 }
767}820}
...@@ -925,6 +978,8 @@ fn ElfFile(comptime is_64: bool) type {...@@ -925,6 +978,8 @@ fn ElfFile(comptime is_64: bool) type {
925 debuglink: ?DebugLink = null,978 debuglink: ?DebugLink = null,
926 compress_debug: bool = false,979 compress_debug: bool = false,
927 add_section: ?AddSectionOptions = null,980 add_section: ?AddSectionOptions = null,
981 set_section_alignment: ?SectionAlignmentOptions = null,
982 set_section_flags: ?SectionFlagsOptions = null,
928 };983 };
929 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {984 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
930 var arena = std.heap.ArenaAllocator.init(gpa);985 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -1191,14 +1246,19 @@ fn ElfFile(comptime is_64: bool) type {...@@ -1191,14 +1246,19 @@ fn ElfFile(comptime is_64: bool) type {
11911246
1192 // add user section1247 // add user section
1193 if (options.add_section) |add_section| {1248 if (options.add_section) |add_section| {
1194 var section_file = fs.cwd().openFile(add_section.file, .{}) catch |err|1249 var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
1195 fatal("unable to open '{s}': {s}", .{ add_section.file, @errorName(err) });1250 fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
1196 defer section_file.close();1251 defer section_file.close();
11971252
1198 const max_size = std.math.maxInt(usize);1253 const max_size = std.math.maxInt(usize);
1199 const payload = try section_file.readToEndAlloc(arena.allocator(), max_size);1254 const payload = try section_file.readToEndAlloc(arena.allocator(), max_size);
1200 const flags = 0; // TODO: 19009: support --set-section-flags1255 const flags = 0; // TODO: 19009: support --set-section-flags
1201 const alignment = 4; // TODO: 19009: support --set-section-alignment1256 const alignment = align_bytes: {
1257 if (options.set_section_alignment) |set_align| {
1258 if (std.mem.eql(u8, set_align.section_name, add_section.section_name)) break :align_bytes set_align.alignment;
1259 }
1260 break :align_bytes 4;
1261 };
12021262
1203 dest_sections[dest_section_idx] = Elf_Shdr{1263 dest_sections[dest_section_idx] = Elf_Shdr{
1204 .sh_name = user_section_name,1264 .sh_name = user_section_name,
...@@ -1218,6 +1278,16 @@ fn ElfFile(comptime is_64: bool) type {...@@ -1218,6 +1278,16 @@ fn ElfFile(comptime is_64: bool) type {
1218 eof_offset += @as(Elf_OffSize, @intCast(payload.len));1278 eof_offset += @as(Elf_OffSize, @intCast(payload.len));
1219 }1279 }
12201280
1281 // overwrite section alignment
1282 {
1283 // TODO: 19009: NYI
1284 }
1285
1286 // overwrite section flags
1287 {
1288 // TODO: 19009: NYI
1289 }
1290
1221 assert(dest_section_idx == new_shnum);1291 assert(dest_section_idx == new_shnum);
1222 break :blk dest_sections;1292 break :blk dest_sections;
1223 };1293 };
...@@ -1462,9 +1532,9 @@ fn splitOption(option: []const u8) ?SplitResult {...@@ -1462,9 +1532,9 @@ fn splitOption(option: []const u8) ?SplitResult {
14621532
1463test "Split option" {1533test "Split option" {
1464 {1534 {
1465 const split = splitOption("a=123");1535 const split = splitOption(".abc=123");
1466 try std.testing.expect(split != null);1536 try std.testing.expect(split != null);
1467 try std.testing.expectEqualStrings("a", split.?.first);1537 try std.testing.expectEqualStrings(".abc", split.?.first);
1468 try std.testing.expectEqualStrings("123", split.?.second);1538 try std.testing.expectEqualStrings("123", split.?.second);
1469 }1539 }
14701540