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
log8f55efc1af9de1ae00aa07bfa6fbbcfeeca02eb4
treee495a7d066bfbc8335741749a813e939c7108ee3
parent8cd7a9e5fc0be2328388acb138ccce77a45603bc

19009: zig objcopy: integrate section flags for --set-section-flags command


1 files changed, 57 insertions(+), 42 deletions(-)

lib/compiler/objcopy.zig+57-42
...@@ -41,8 +41,8 @@ fn cmdObjCopy(...@@ -41,8 +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;44 var set_section_alignment: ?SetSectionAlignmentOptions = null;
45 var set_section_flags: ?SectionFlagsOptions = null;45 var set_section_flags: ?SetSectionFlagsOptions = null;
46 while (i < args.len) : (i += 1) {46 while (i < args.len) : (i += 1) {
47 const arg = args[i];47 const arg = args[i];
48 if (!mem.startsWith(u8, arg, "-")) {48 if (!mem.startsWith(u8, arg, "-")) {
...@@ -125,9 +125,7 @@ fn cmdObjCopy(...@@ -125,9 +125,7 @@ fn cmdObjCopy(
125 if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});125 if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
126126
127 if (splitOption(args[i])) |split| {127 if (splitOption(args[i])) |split| {
128 const flags = parseSectionFlags(split.second);128 set_section_flags = .{ .section_name = split.first, .flags = parseSectionFlags(split.second) };
129 _ = flags; // TODO: 19009: integrate
130 set_section_flags = .{ .section_name = split.first, .flags = split.second };
131 } else {129 } else {
132 fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]});130 fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]});
133 }131 }
...@@ -282,8 +280,8 @@ pub const EmitRawElfOptions = struct {...@@ -282,8 +280,8 @@ pub const EmitRawElfOptions = struct {
282 only_section: ?[]const u8 = null,280 only_section: ?[]const u8 = null,
283 pad_to: ?u64 = null,281 pad_to: ?u64 = null,
284 add_section: ?AddSectionOptions,282 add_section: ?AddSectionOptions,
285 set_section_alignment: ?SectionAlignmentOptions,283 set_section_alignment: ?SetSectionAlignmentOptions,
286 set_section_flags: ?SectionFlagsOptions,284 set_section_flags: ?SetSectionFlagsOptions,
287};285};
288286
289const AddSectionOptions = struct {287const AddSectionOptions = struct {
...@@ -292,15 +290,14 @@ const AddSectionOptions = struct {...@@ -292,15 +290,14 @@ const AddSectionOptions = struct {
292 file_path: []const u8,290 file_path: []const u8,
293};291};
294292
295const SectionAlignmentOptions = struct {293const SetSectionAlignmentOptions = struct {
296 section_name: []const u8,294 section_name: []const u8,
297 alignment: u32,295 alignment: u32,
298};296};
299297
300const SectionFlagsOptions = struct {298const SetSectionFlagsOptions = struct {
301 section_name: []const u8,299 section_name: []const u8,
302 // comma separated string representation of the SHF_x flags for Shdr.sh_flags300 flags: SectionFlags,
303 flags: []const u8,
304};301};
305302
306fn emitElf(303fn emitElf(
...@@ -744,8 +741,8 @@ const StripElfOptions = struct {...@@ -744,8 +741,8 @@ const StripElfOptions = struct {
744 only_keep_debug: bool = false,741 only_keep_debug: bool = false,
745 compress_debug: bool = false,742 compress_debug: bool = false,
746 add_section: ?AddSectionOptions,743 add_section: ?AddSectionOptions,
747 set_section_alignment: ?SectionAlignmentOptions,744 set_section_alignment: ?SetSectionAlignmentOptions,
748 set_section_flags: ?SectionFlagsOptions,745 set_section_flags: ?SetSectionFlagsOptions,
749};746};
750747
751fn stripElf(748fn stripElf(
...@@ -980,8 +977,8 @@ fn ElfFile(comptime is_64: bool) type {...@@ -980,8 +977,8 @@ fn ElfFile(comptime is_64: bool) type {
980 debuglink: ?DebugLink = null,977 debuglink: ?DebugLink = null,
981 compress_debug: bool = false,978 compress_debug: bool = false,
982 add_section: ?AddSectionOptions = null,979 add_section: ?AddSectionOptions = null,
983 set_section_alignment: ?SectionAlignmentOptions = null,980 set_section_alignment: ?SetSectionAlignmentOptions = null,
984 set_section_flags: ?SectionFlagsOptions = null,981 set_section_flags: ?SetSectionFlagsOptions = null,
985 };982 };
986 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {983 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
987 var arena = std.heap.ArenaAllocator.init(gpa);984 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -1246,7 +1243,7 @@ fn ElfFile(comptime is_64: bool) type {...@@ -1246,7 +1243,7 @@ fn ElfFile(comptime is_64: bool) type {
1246 eof_offset += @as(Elf_OffSize, @intCast(payload.len));1243 eof_offset += @as(Elf_OffSize, @intCast(payload.len));
1247 }1244 }
12481245
1249 // add user section1246 // --add-section
1250 if (options.add_section) |add_section| {1247 if (options.add_section) |add_section| {
1251 var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|1248 var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
1252 fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });1249 fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
...@@ -1303,9 +1300,41 @@ fn ElfFile(comptime is_64: bool) type {...@@ -1303,9 +1300,41 @@ fn ElfFile(comptime is_64: bool) type {
1303 for (updated_section_header) |*section| {1300 for (updated_section_header) |*section| {
1304 const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));1301 const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
1305 if (std.mem.eql(u8, section_name, set_flags.section_name)) {1302 if (std.mem.eql(u8, section_name, set_flags.section_name)) {
1306 // TODO: 19009: map flags string to bitfield.1303 section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly"
1307 // section.sh_flags = set_flags.flags;1304 const f = set_flags.flags;
1308 section.sh_flags = 0;1305
1306 // Supporting a subset of GNU and LLVM objcopy for ELF only
1307 // GNU:
1308 // alloc: add SHF_ALLOC
1309 // contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
1310 // load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
1311 // noload: not ELF relevant
1312 // readonly: clear default SHF_WRITE flag
1313 // code: add SHF_EXECINSTR
1314 // data: not ELF relevant
1315 // rom: ignored
1316 // exclude: add SHF_EXCLUDE
1317 // share: not ELF relevant
1318 // debug: not ELF relevant
1319 // large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64
1320 if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC;
1321 if (f.contents or f.load) {
1322 if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS;
1323 }
1324 if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE);
1325 if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR;
1326 if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE;
1327 if (f.large) {
1328 if (updated_elf_header.e_machine != std.elf.EM.X86_64)
1329 fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{});
1330 section.sh_flags |= std.elf.SHF_X86_64_LARGE;
1331 }
1332
1333 // LLVM:
1334 // merge: add SHF_MERGE
1335 // strings: add SHF_STRINGS
1336 if (f.merge) section.sh_flags |= std.elf.SHF_MERGE;
1337 if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS;
1309 break;1338 break;
1310 }1339 }
1311 } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name});1340 } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name});
...@@ -1535,24 +1564,6 @@ const ElfFileHelper = struct {...@@ -1535,24 +1564,6 @@ const ElfFileHelper = struct {
1535 }1564 }
1536};1565};
15371566
1538/// Supporting a subset of GNU and LLVM objcopy for ELF only
1539/// GNU:
1540/// alloc: add SHF_ALLOC
1541/// contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
1542/// load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
1543/// noload: not supported
1544/// readonly: clear default SHF_WRITE flag
1545/// code: add SHF_EXECINSTR
1546/// data: not supported
1547/// rom: not supported
1548/// exclude: add SHF_EXCLUDE
1549/// share: not supported
1550/// debug: not supported
1551/// large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64
1552///
1553/// LLVM:
1554/// merge: add SHF_MERGE
1555/// strings: add SHF_STRINGS
1556const SectionFlags = packed struct {1567const SectionFlags = packed struct {
1557 alloc: bool = false,1568 alloc: bool = false,
1558 contents: bool = false,1569 contents: bool = false,
...@@ -1604,29 +1615,33 @@ fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags {...@@ -1604,29 +1615,33 @@ fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags {
1604 } else if (std.mem.eql(u8, string, "strings")) {1615 } else if (std.mem.eql(u8, string, "strings")) {
1605 flags.strings = true;1616 flags.strings = true;
1606 } else {1617 } else {
1607 std.log.err("Skipping unrecognized section flag '{s}'", .{string});1618 std.log.warn("Skipping unrecognized section flag '{s}'", .{string});
1608 }1619 }
1609 }1620 }
1610 };1621 };
16111622
1612 var flags = SectionFlags{};1623 var flags = SectionFlags{};
1613 var start: usize = 0;1624 var offset: usize = 0;
1614 for (comma_separated_flags, 0..) |c, i| {1625 for (comma_separated_flags, 0..) |c, i| {
1615 if (c == ',') {1626 if (c == ',') {
1616 defer start = i + 1;1627 defer offset = i + 1;
1617 const string = comma_separated_flags[start..i];1628 const string = comma_separated_flags[offset..i];
1618 P.parse(&flags, string);1629 P.parse(&flags, string);
1619 }1630 }
1620 }1631 }
1621 P.parse(&flags, comma_separated_flags[start..]);1632 P.parse(&flags, comma_separated_flags[offset..]);
1622 return flags;1633 return flags;
1623}1634}
16241635
1625test "Parse section flags" {1636test "Parse section flags" {
1626 const F = SectionFlags;1637 const F = SectionFlags;
1627 try std.testing.expectEqual(F{}, parseSectionFlags(""));1638 try std.testing.expectEqual(F{}, parseSectionFlags(""));
1639 try std.testing.expectEqual(F{}, parseSectionFlags(","));
1640 try std.testing.expectEqual(F{}, parseSectionFlags("abc"));
1628 try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc"));1641 try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc"));
1642 try std.testing.expectEqual(F{ .data = true }, parseSectionFlags("data,"));
1629 try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code"));1643 try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code"));
1644 try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code,not_supported"));
1630}1645}
16311646
1632const SplitResult = struct { first: []const u8, second: []const u8 };1647const SplitResult = struct { first: []const u8, second: []const u8 };