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(
4141 var compress_debug_sections: bool = false;
4242 var listen = false;
4343 var add_section: ?AddSectionOptions = null;
44 var set_section_alignment: ?SectionAlignmentOptions = null;
45 var set_section_flags: ?SectionFlagsOptions = null;
4446 while (i < args.len) : (i += 1) {
4547 const arg = args[i];
4648 if (!mem.startsWith(u8, arg, "-")) {
......@@ -105,12 +107,34 @@ fn cmdObjCopy(
105107 i += 1;
106108 if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
107109 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 }
108132 } else if (mem.eql(u8, arg, "--add-section")) {
109133 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
112136 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 };
114138 } else {
115139 fatal("unrecognized argument: '{s}', expecting <name>=<file>", .{args[i]});
116140 }
......@@ -167,6 +191,8 @@ fn cmdObjCopy(
167191 .only_section = only_section,
168192 .pad_to = pad_to,
169193 .add_section = add_section,
194 .set_section_alignment = set_section_alignment,
195 .set_section_flags = set_section_flags,
170196 });
171197 },
172198 .elf => {
......@@ -187,6 +213,8 @@ fn cmdObjCopy(
187213 .extract_to = opt_extract,
188214 .compress_debug = compress_debug_sections,
189215 .add_section = add_section,
216 .set_section_alignment = set_section_alignment,
217 .set_section_flags = set_section_flags,
190218 });
191219 return std.process.cleanExit();
192220 },
......@@ -229,19 +257,21 @@ const usage =
229257 \\Usage: zig objcopy [options] input output
230258 \\
231259 \\Options:
232 \\ -h, --help Print this help and exit
233 \\ --output-target=<value> Format of the output file
234 \\ -O <value> Alias for --output-target
235 \\ --only-section=<section> Remove all but <section>
236 \\ -j <value> Alias for --only-section
237 \\ --pad-to <addr> Pad the last section up to address <addr>
238 \\ --strip-debug, -g Remove all debug sections from the output.
239 \\ --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.
241 \\ --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.
243 \\ --compress-debug-sections Compress DWARF debug sections with zlib
244 \\ --add-section <name>=<file> Add file content from <file> with the section name <name>.
260 \\ -h, --help Print this help and exit
261 \\ --output-target=<value> Format of the output file
262 \\ -O <value> Alias for --output-target
263 \\ --only-section=<section> Remove all but <section>
264 \\ -j <value> Alias for --only-section
265 \\ --pad-to <addr> Pad the last section up to address <addr>
266 \\ --strip-debug, -g Remove all debug sections from the output.
267 \\ --strip-all, -S Remove all debug sections and symbol table from the output.
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.
269 \\ --add-gnu-debuglink=<file> Creates a .gnu_debuglink section which contains a reference to <file> and adds it to the output file.
270 \\ --extract-to <file> Extract the removed sections into <file>, and add a .gnu-debuglink section.
271 \\ --compress-debug-sections Compress DWARF debug sections with zlib
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>.
245275 \\
246276;
247277
......@@ -250,11 +280,25 @@ pub const EmitRawElfOptions = struct {
250280 only_section: ?[]const u8 = null,
251281 pad_to: ?u64 = null,
252282 add_section: ?AddSectionOptions,
283 set_section_alignment: ?SectionAlignmentOptions,
284 set_section_flags: ?SectionFlagsOptions,
253285};
254286
255287const AddSectionOptions = struct {
256288 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,
258302};
259303
260304fn emitElf(
......@@ -698,6 +742,8 @@ const StripElfOptions = struct {
698742 only_keep_debug: bool = false,
699743 compress_debug: bool = false,
700744 add_section: ?AddSectionOptions,
745 set_section_alignment: ?SectionAlignmentOptions,
746 set_section_flags: ?SectionFlagsOptions,
701747};
702748
703749fn stripElf(
......@@ -761,7 +807,14 @@ fn stripElf(
761807 }
762808
763809 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 });
765818 },
766819 }
767820}
......@@ -925,6 +978,8 @@ fn ElfFile(comptime is_64: bool) type {
925978 debuglink: ?DebugLink = null,
926979 compress_debug: bool = false,
927980 add_section: ?AddSectionOptions = null,
981 set_section_alignment: ?SectionAlignmentOptions = null,
982 set_section_flags: ?SectionFlagsOptions = null,
928983 };
929984 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
930985 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -1191,14 +1246,19 @@ fn ElfFile(comptime is_64: bool) type {
11911246
11921247 // add user section
11931248 if (options.add_section) |add_section| {
1194 var section_file = fs.cwd().openFile(add_section.file, .{}) catch |err|
1195 fatal("unable to open '{s}': {s}", .{ add_section.file, @errorName(err) });
1249 var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
1250 fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
11961251 defer section_file.close();
11971252
11981253 const max_size = std.math.maxInt(usize);
11991254 const payload = try section_file.readToEndAlloc(arena.allocator(), max_size);
12001255 const flags = 0; // TODO: 19009: support --set-section-flags
1201 const alignment = 4; // TODO: 19009: support --set-section-alignment
1256 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
12031263 dest_sections[dest_section_idx] = Elf_Shdr{
12041264 .sh_name = user_section_name,
......@@ -1218,6 +1278,16 @@ fn ElfFile(comptime is_64: bool) type {
12181278 eof_offset += @as(Elf_OffSize, @intCast(payload.len));
12191279 }
12201280
1281 // overwrite section alignment
1282 {
1283 // TODO: 19009: NYI
1284 }
1285
1286 // overwrite section flags
1287 {
1288 // TODO: 19009: NYI
1289 }
1290
12211291 assert(dest_section_idx == new_shnum);
12221292 break :blk dest_sections;
12231293 };
......@@ -1462,9 +1532,9 @@ fn splitOption(option: []const u8) ?SplitResult {
14621532
14631533test "Split option" {
14641534 {
1465 const split = splitOption("a=123");
1535 const split = splitOption(".abc=123");
14661536 try std.testing.expect(split != null);
1467 try std.testing.expectEqualStrings("a", split.?.first);
1537 try std.testing.expectEqualStrings(".abc", split.?.first);
14681538 try std.testing.expectEqualStrings("123", split.?.second);
14691539 }
14701540