| ... | @@ -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}); |
| 126 | | 126 | |
| 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 | }; |
| 288 | | 286 | |
| 289 | const AddSectionOptions = struct { | 287 | const 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 | }; |
| 294 | | 292 | |
| 295 | const SectionAlignmentOptions = struct { | 293 | const SetSectionAlignmentOptions = struct { |
| 296 | section_name: []const u8, | 294 | section_name: []const u8, |
| 297 | alignment: u32, | 295 | alignment: u32, |
| 298 | }; | 296 | }; |
| 299 | | 297 | |
| 300 | const SectionFlagsOptions = struct { | 298 | const 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_flags | 300 | flags: SectionFlags, |
| 303 | flags: []const u8, | | |
| 304 | }; | 301 | }; |
| 305 | | 302 | |
| 306 | fn emitElf( | 303 | fn 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 | }; |
| 750 | | 747 | |
| 751 | fn stripElf( | 748 | fn 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 | } |
| 1248 | | 1245 | |
| 1249 | // add user section | 1246 | // --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 | }; |
| 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 | const SectionFlags = packed struct { | 1567 | const 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 | }; |
| 1611 | | 1622 | |
| 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 | } |
| 1624 | | 1635 | |
| 1625 | test "Parse section flags" { | 1636 | test "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 | } |
| 1631 | | 1646 | |
| 1632 | const SplitResult = struct { first: []const u8, second: []const u8 }; | 1647 | const SplitResult = struct { first: []const u8, second: []const u8 }; |