| ... | ... | @@ -41,8 +41,8 @@ fn cmdObjCopy( |
| 41 | 41 | var compress_debug_sections: bool = false; |
| 42 | 42 | var listen = false; |
| 43 | 43 | var add_section: ?AddSectionOptions = null; |
| 44 | | var set_section_alignment: ?SectionAlignmentOptions = null; |
| 45 | | var set_section_flags: ?SectionFlagsOptions = null; |
| 44 | var set_section_alignment: ?SetSectionAlignmentOptions = null; |
| 45 | var set_section_flags: ?SetSectionFlagsOptions = null; |
| 46 | 46 | while (i < args.len) : (i += 1) { |
| 47 | 47 | const arg = args[i]; |
| 48 | 48 | if (!mem.startsWith(u8, arg, "-")) { |
| ... | ... | @@ -125,9 +125,7 @@ fn cmdObjCopy( |
| 125 | 125 | if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg}); |
| 126 | 126 | |
| 127 | 127 | if (splitOption(args[i])) |split| { |
| 128 | | const flags = parseSectionFlags(split.second); |
| 129 | | _ = flags; // TODO: 19009: integrate |
| 130 | | set_section_flags = .{ .section_name = split.first, .flags = split.second }; |
| 128 | set_section_flags = .{ .section_name = split.first, .flags = parseSectionFlags(split.second) }; |
| 131 | 129 | } else { |
| 132 | 130 | fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]}); |
| 133 | 131 | } |
| ... | ... | @@ -282,8 +280,8 @@ pub const EmitRawElfOptions = struct { |
| 282 | 280 | only_section: ?[]const u8 = null, |
| 283 | 281 | pad_to: ?u64 = null, |
| 284 | 282 | add_section: ?AddSectionOptions, |
| 285 | | set_section_alignment: ?SectionAlignmentOptions, |
| 286 | | set_section_flags: ?SectionFlagsOptions, |
| 283 | set_section_alignment: ?SetSectionAlignmentOptions, |
| 284 | set_section_flags: ?SetSectionFlagsOptions, |
| 287 | 285 | }; |
| 288 | 286 | |
| 289 | 287 | const AddSectionOptions = struct { |
| ... | ... | @@ -292,15 +290,14 @@ const AddSectionOptions = struct { |
| 292 | 290 | file_path: []const u8, |
| 293 | 291 | }; |
| 294 | 292 | |
| 295 | | const SectionAlignmentOptions = struct { |
| 293 | const SetSectionAlignmentOptions = struct { |
| 296 | 294 | section_name: []const u8, |
| 297 | 295 | alignment: u32, |
| 298 | 296 | }; |
| 299 | 297 | |
| 300 | | const SectionFlagsOptions = struct { |
| 298 | const SetSectionFlagsOptions = struct { |
| 301 | 299 | section_name: []const u8, |
| 302 | | // comma separated string representation of the SHF_x flags for Shdr.sh_flags |
| 303 | | flags: []const u8, |
| 300 | flags: SectionFlags, |
| 304 | 301 | }; |
| 305 | 302 | |
| 306 | 303 | fn emitElf( |
| ... | ... | @@ -744,8 +741,8 @@ const StripElfOptions = struct { |
| 744 | 741 | only_keep_debug: bool = false, |
| 745 | 742 | compress_debug: bool = false, |
| 746 | 743 | add_section: ?AddSectionOptions, |
| 747 | | set_section_alignment: ?SectionAlignmentOptions, |
| 748 | | set_section_flags: ?SectionFlagsOptions, |
| 744 | set_section_alignment: ?SetSectionAlignmentOptions, |
| 745 | set_section_flags: ?SetSectionFlagsOptions, |
| 749 | 746 | }; |
| 750 | 747 | |
| 751 | 748 | fn stripElf( |
| ... | ... | @@ -980,8 +977,8 @@ fn ElfFile(comptime is_64: bool) type { |
| 980 | 977 | debuglink: ?DebugLink = null, |
| 981 | 978 | compress_debug: bool = false, |
| 982 | 979 | add_section: ?AddSectionOptions = null, |
| 983 | | set_section_alignment: ?SectionAlignmentOptions = null, |
| 984 | | set_section_flags: ?SectionFlagsOptions = null, |
| 980 | set_section_alignment: ?SetSectionAlignmentOptions = null, |
| 981 | set_section_flags: ?SetSectionFlagsOptions = null, |
| 985 | 982 | }; |
| 986 | 983 | fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void { |
| 987 | 984 | var arena = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -1246,7 +1243,7 @@ fn ElfFile(comptime is_64: bool) type { |
| 1246 | 1243 | eof_offset += @as(Elf_OffSize, @intCast(payload.len)); |
| 1247 | 1244 | } |
| 1248 | 1245 | |
| 1249 | | // add user section |
| 1246 | // --add-section |
| 1250 | 1247 | if (options.add_section) |add_section| { |
| 1251 | 1248 | var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err| |
| 1252 | 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 | 1300 | for (updated_section_header) |*section| { |
| 1304 | 1301 | const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name]))); |
| 1305 | 1302 | if (std.mem.eql(u8, section_name, set_flags.section_name)) { |
| 1306 | | // TODO: 19009: map flags string to bitfield. |
| 1307 | | // section.sh_flags = set_flags.flags; |
| 1308 | | section.sh_flags = 0; |
| 1303 | section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly" |
| 1304 | const f = set_flags.flags; |
| 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 | 1338 | break; |
| 1310 | 1339 | } |
| 1311 | 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 | 1564 | } |
| 1536 | 1565 | }; |
| 1537 | 1566 | |
| 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 |
| 1556 | 1567 | const SectionFlags = packed struct { |
| 1557 | 1568 | alloc: bool = false, |
| 1558 | 1569 | contents: bool = false, |
| ... | ... | @@ -1604,29 +1615,33 @@ fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags { |
| 1604 | 1615 | } else if (std.mem.eql(u8, string, "strings")) { |
| 1605 | 1616 | flags.strings = true; |
| 1606 | 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 | }; |
| 1611 | 1622 | |
| 1612 | 1623 | var flags = SectionFlags{}; |
| 1613 | | var start: usize = 0; |
| 1624 | var offset: usize = 0; |
| 1614 | 1625 | for (comma_separated_flags, 0..) |c, i| { |
| 1615 | 1626 | if (c == ',') { |
| 1616 | | defer start = i + 1; |
| 1617 | | const string = comma_separated_flags[start..i]; |
| 1627 | defer offset = i + 1; |
| 1628 | const string = comma_separated_flags[offset..i]; |
| 1618 | 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 | 1633 | return flags; |
| 1623 | 1634 | } |
| 1624 | 1635 | |
| 1625 | 1636 | test "Parse section flags" { |
| 1626 | 1637 | const F = SectionFlags; |
| 1627 | 1638 | try std.testing.expectEqual(F{}, parseSectionFlags("")); |
| 1639 | try std.testing.expectEqual(F{}, parseSectionFlags(",")); |
| 1640 | try std.testing.expectEqual(F{}, parseSectionFlags("abc")); |
| 1628 | 1641 | try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc")); |
| 1642 | try std.testing.expectEqual(F{ .data = true }, parseSectionFlags("data,")); |
| 1629 | 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 | } |
| 1631 | 1646 | |
| 1632 | 1647 | const SplitResult = struct { first: []const u8, second: []const u8 }; |