| ... | @@ -125,6 +125,8 @@ fn cmdObjCopy( | ... | @@ -125,6 +125,8 @@ 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}); |
| 126 | | 126 | |
| 127 | if (splitOption(args[i])) |split| { | 127 | if (splitOption(args[i])) |split| { |
| | 128 | const flags = parseSectionFlags(split.second); |
| | 129 | _ = flags; // TODO: 19009: integrate |
| 128 | set_section_flags = .{ .section_name = split.first, .flags = split.second }; | 130 | set_section_flags = .{ .section_name = split.first, .flags = split.second }; |
| 129 | } else { | 131 | } else { |
| 130 | fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]}); | 132 | fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]}); |
| ... | @@ -1533,6 +1535,100 @@ const ElfFileHelper = struct { | ... | @@ -1533,6 +1535,100 @@ const ElfFileHelper = struct { |
| 1533 | } | 1535 | } |
| 1534 | }; | 1536 | }; |
| 1535 | | 1537 | |
| | 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 | const SectionFlags = packed struct { |
| | 1557 | alloc: bool = false, |
| | 1558 | contents: bool = false, |
| | 1559 | load: bool = false, |
| | 1560 | noload: bool = false, |
| | 1561 | readonly: bool = false, |
| | 1562 | code: bool = false, |
| | 1563 | data: bool = false, |
| | 1564 | rom: bool = false, |
| | 1565 | exclude: bool = false, |
| | 1566 | shared: bool = false, |
| | 1567 | debug: bool = false, |
| | 1568 | large: bool = false, |
| | 1569 | merge: bool = false, |
| | 1570 | strings: bool = false, |
| | 1571 | }; |
| | 1572 | |
| | 1573 | fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags { |
| | 1574 | const P = struct { |
| | 1575 | fn parse(flags: *SectionFlags, string: []const u8) void { |
| | 1576 | if (string.len == 0) return; |
| | 1577 | |
| | 1578 | if (std.mem.eql(u8, string, "alloc")) { |
| | 1579 | flags.alloc = true; |
| | 1580 | } else if (std.mem.eql(u8, string, "contents")) { |
| | 1581 | flags.contents = true; |
| | 1582 | } else if (std.mem.eql(u8, string, "load")) { |
| | 1583 | flags.load = true; |
| | 1584 | } else if (std.mem.eql(u8, string, "noload")) { |
| | 1585 | flags.noload = true; |
| | 1586 | } else if (std.mem.eql(u8, string, "readonly")) { |
| | 1587 | flags.readonly = true; |
| | 1588 | } else if (std.mem.eql(u8, string, "code")) { |
| | 1589 | flags.code = true; |
| | 1590 | } else if (std.mem.eql(u8, string, "data")) { |
| | 1591 | flags.data = true; |
| | 1592 | } else if (std.mem.eql(u8, string, "rom")) { |
| | 1593 | flags.rom = true; |
| | 1594 | } else if (std.mem.eql(u8, string, "exclude")) { |
| | 1595 | flags.exclude = true; |
| | 1596 | } else if (std.mem.eql(u8, string, "shared")) { |
| | 1597 | flags.shared = true; |
| | 1598 | } else if (std.mem.eql(u8, string, "debug")) { |
| | 1599 | flags.debug = true; |
| | 1600 | } else if (std.mem.eql(u8, string, "large")) { |
| | 1601 | flags.large = true; |
| | 1602 | } else if (std.mem.eql(u8, string, "merge")) { |
| | 1603 | flags.merge = true; |
| | 1604 | } else if (std.mem.eql(u8, string, "strings")) { |
| | 1605 | flags.strings = true; |
| | 1606 | } else { |
| | 1607 | std.log.err("Skipping unrecognized section flag '{s}'", .{string}); |
| | 1608 | } |
| | 1609 | } |
| | 1610 | }; |
| | 1611 | |
| | 1612 | var flags = SectionFlags{}; |
| | 1613 | var start: usize = 0; |
| | 1614 | for (comma_separated_flags, 0..) |c, i| { |
| | 1615 | if (c == ',') { |
| | 1616 | defer start = i + 1; |
| | 1617 | const string = comma_separated_flags[start..i]; |
| | 1618 | P.parse(&flags, string); |
| | 1619 | } |
| | 1620 | } |
| | 1621 | P.parse(&flags, comma_separated_flags[start..]); |
| | 1622 | return flags; |
| | 1623 | } |
| | 1624 | |
| | 1625 | test "Parse section flags" { |
| | 1626 | const F = SectionFlags; |
| | 1627 | try std.testing.expectEqual(F{}, parseSectionFlags("")); |
| | 1628 | try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc")); |
| | 1629 | try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code")); |
| | 1630 | } |
| | 1631 | |
| 1536 | const SplitResult = struct { first: []const u8, second: []const u8 }; | 1632 | const SplitResult = struct { first: []const u8, second: []const u8 }; |
| 1537 | | 1633 | |
| 1538 | fn splitOption(option: []const u8) ?SplitResult { | 1634 | fn splitOption(option: []const u8) ?SplitResult { |