From f72961ee306408cdd3ee4ef5a8bc5301f94fc7e5 Mon Sep 17 00:00:00 2001 From: Patrick Wickenhaeuser <35903594+patrickwick@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:38:34 +0200 Subject: [PATCH] 19009: add --set-section-alignment and --set-section-flags arguments to zig objcopy --- lib/compiler/objcopy.zig | 116 +++++++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 23 deletions(-) diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index f534763f57..51bdab5b17 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -41,6 +41,8 @@ fn cmdObjCopy( var compress_debug_sections: bool = false; var listen = false; var add_section: ?AddSectionOptions = null; + var set_section_alignment: ?SectionAlignmentOptions = null; + var set_section_flags: ?SectionFlagsOptions = null; while (i < args.len) : (i += 1) { const arg = args[i]; if (!mem.startsWith(u8, arg, "-")) { @@ -105,12 +107,34 @@ fn cmdObjCopy( i += 1; if (i >= args.len) fatal("expected another argument after '{s}'", .{arg}); opt_extract = args[i]; - } else if (mem.eql(u8, arg, "--add-section")) { + } else if (mem.eql(u8, arg, "--set-section-alignment")) { i += 1; - if (i >= args.len) fatal("expected name and filename arguments after '{s}'", .{arg}); + if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg}); if (splitOption(args[i])) |split| { - add_section = .{ .section_name = split.first, .file = split.second }; + const alignment = std.fmt.parseInt(u32, split.second, 10) catch |err| { + fatal("unable to parse alignment number: '{s}': {s}", .{ split.second, @errorName(err) }); + }; + if (!std.math.isPowerOfTwo(alignment)) fatal("alignment must be a power of two", .{}); + set_section_alignment = .{ .section_name = split.first, .alignment = alignment }; + } else { + fatal("unrecognized argument: '{s}', expecting =", .{args[i]}); + } + } else if (mem.eql(u8, arg, "--set-section-flags")) { + i += 1; + if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg}); + + if (splitOption(args[i])) |split| { + set_section_flags = .{ .section_name = split.first, .flags = split.second }; + } else { + fatal("unrecognized argument: '{s}', expecting =", .{args[i]}); + } + } else if (mem.eql(u8, arg, "--add-section")) { + i += 1; + if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg}); + + if (splitOption(args[i])) |split| { + add_section = .{ .section_name = split.first, .file_path = split.second }; } else { fatal("unrecognized argument: '{s}', expecting =", .{args[i]}); } @@ -167,6 +191,8 @@ fn cmdObjCopy( .only_section = only_section, .pad_to = pad_to, .add_section = add_section, + .set_section_alignment = set_section_alignment, + .set_section_flags = set_section_flags, }); }, .elf => { @@ -187,6 +213,8 @@ fn cmdObjCopy( .extract_to = opt_extract, .compress_debug = compress_debug_sections, .add_section = add_section, + .set_section_alignment = set_section_alignment, + .set_section_flags = set_section_flags, }); return std.process.cleanExit(); }, @@ -229,19 +257,21 @@ const usage = \\Usage: zig objcopy [options] input output \\ \\Options: - \\ -h, --help Print this help and exit - \\ --output-target= Format of the output file - \\ -O Alias for --output-target - \\ --only-section=
Remove all but
- \\ -j Alias for --only-section - \\ --pad-to Pad the last section up to address - \\ --strip-debug, -g Remove all debug sections from the output. - \\ --strip-all, -S Remove all debug sections and symbol table from the output. - \\ --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. - \\ --add-gnu-debuglink= Creates a .gnu_debuglink section which contains a reference to and adds it to the output file. - \\ --extract-to Extract the removed sections into , and add a .gnu-debuglink section. - \\ --compress-debug-sections Compress DWARF debug sections with zlib - \\ --add-section = Add file content from with the section name . + \\ -h, --help Print this help and exit + \\ --output-target= Format of the output file + \\ -O Alias for --output-target + \\ --only-section=
Remove all but
+ \\ -j Alias for --only-section + \\ --pad-to Pad the last section up to address + \\ --strip-debug, -g Remove all debug sections from the output. + \\ --strip-all, -S Remove all debug sections and symbol table from the output. + \\ --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. + \\ --add-gnu-debuglink= Creates a .gnu_debuglink section which contains a reference to and adds it to the output file. + \\ --extract-to Extract the removed sections into , and add a .gnu-debuglink section. + \\ --compress-debug-sections Compress DWARF debug sections with zlib + \\ --set-section-alignment = Set alignment of section to bytes. Must be a power of two. + \\ --set-section-flags = Set flags of section to represented as a comma separated set of flags. + \\ --add-section = Add file content from with the section name . \\ ; @@ -250,11 +280,25 @@ pub const EmitRawElfOptions = struct { only_section: ?[]const u8 = null, pad_to: ?u64 = null, add_section: ?AddSectionOptions, + set_section_alignment: ?SectionAlignmentOptions, + set_section_flags: ?SectionFlagsOptions, }; const AddSectionOptions = struct { section_name: []const u8, - file: []const u8, + // file to store in new section + file_path: []const u8, +}; + +const SectionAlignmentOptions = struct { + section_name: []const u8, + alignment: u32, +}; + +const SectionFlagsOptions = struct { + section_name: []const u8, + // comma separated string representation of the SHF_x flags for Shdr.sh_flags + flags: []const u8, }; fn emitElf( @@ -698,6 +742,8 @@ const StripElfOptions = struct { only_keep_debug: bool = false, compress_debug: bool = false, add_section: ?AddSectionOptions, + set_section_alignment: ?SectionAlignmentOptions, + set_section_flags: ?SectionFlagsOptions, }; fn stripElf( @@ -761,7 +807,14 @@ fn stripElf( } const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null; - try elf_file.emit(allocator, out_file, in_file, .{ .section_filter = filter, .debuglink = debuglink, .compress_debug = options.compress_debug, .add_section = options.add_section }); + try elf_file.emit(allocator, out_file, in_file, .{ + .section_filter = filter, + .debuglink = debuglink, + .compress_debug = options.compress_debug, + .add_section = options.add_section, + .set_section_alignment = options.set_section_alignment, + .set_section_flags = options.set_section_flags, + }); }, } } @@ -925,6 +978,8 @@ fn ElfFile(comptime is_64: bool) type { debuglink: ?DebugLink = null, compress_debug: bool = false, add_section: ?AddSectionOptions = null, + set_section_alignment: ?SectionAlignmentOptions = null, + set_section_flags: ?SectionFlagsOptions = null, }; fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void { var arena = std.heap.ArenaAllocator.init(gpa); @@ -1191,14 +1246,19 @@ fn ElfFile(comptime is_64: bool) type { // add user section if (options.add_section) |add_section| { - var section_file = fs.cwd().openFile(add_section.file, .{}) catch |err| - fatal("unable to open '{s}': {s}", .{ add_section.file, @errorName(err) }); + var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err| + fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) }); defer section_file.close(); const max_size = std.math.maxInt(usize); const payload = try section_file.readToEndAlloc(arena.allocator(), max_size); const flags = 0; // TODO: 19009: support --set-section-flags - const alignment = 4; // TODO: 19009: support --set-section-alignment + const alignment = align_bytes: { + if (options.set_section_alignment) |set_align| { + if (std.mem.eql(u8, set_align.section_name, add_section.section_name)) break :align_bytes set_align.alignment; + } + break :align_bytes 4; + }; dest_sections[dest_section_idx] = Elf_Shdr{ .sh_name = user_section_name, @@ -1218,6 +1278,16 @@ fn ElfFile(comptime is_64: bool) type { eof_offset += @as(Elf_OffSize, @intCast(payload.len)); } + // overwrite section alignment + { + // TODO: 19009: NYI + } + + // overwrite section flags + { + // TODO: 19009: NYI + } + assert(dest_section_idx == new_shnum); break :blk dest_sections; }; @@ -1462,9 +1532,9 @@ fn splitOption(option: []const u8) ?SplitResult { test "Split option" { { - const split = splitOption("a=123"); + const split = splitOption(".abc=123"); try std.testing.expect(split != null); - try std.testing.expectEqualStrings("a", split.?.first); + try std.testing.expectEqualStrings(".abc", split.?.first); try std.testing.expectEqualStrings("123", split.?.second); }