feature. See also
. The project being documented here (as the example) is the Zig library itself.
objcopy.cmdObjCopy
fn cmdObjCopy(arena: Allocator, io: Io, args: []const []const u8) !void
File
Code
fn cmdObjCopy(arena: Allocator, io: Io, args: []const []const u8) !void {
var i: usize = 0;
var opt_out_fmt: ?std.Target.ObjectFormat = null;
var opt_input: ?[]const u8 = null;
var opt_output: ?[]const u8 = null;
var opt_extract: ?[]const u8 = null;
var opt_add_debuglink: ?[]const u8 = null;
var only_section: ?[]const u8 = null;
var pad_to: ?u64 = null;
var strip_all: bool = false;
var strip_debug: bool = false;
var only_keep_debug: bool = false;
var compress_debug_sections: bool = false;
var listen = false;
var add_section: ?AddSection = null;
var set_section_alignment: ?SetSectionAlignment = null;
var set_section_flags: ?SetSectionFlags = null;
while (i < args.len) : (i += 1) {
const arg = args[i];
if (!mem.startsWith(u8, arg, "-")) {
if (opt_input == null) {
opt_input = arg;
} else if (opt_output == null) {
opt_output = arg;
} else {
fatal("unexpected positional argument: '{s}'", .{arg});
}
} else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
return Io.File.stdout().writeStreamingAll(io, usage);
} else if (mem.eql(u8, arg, "-O") or mem.eql(u8, arg, "--output-target")) {
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
const next_arg = args[i];
if (mem.eql(u8, next_arg, "binary")) {
opt_out_fmt = .raw;
} else {
opt_out_fmt = std.meta.stringToEnum(std.Target.ObjectFormat, next_arg) orelse
fatal("invalid output format: '{s}'", .{next_arg});
}
} else if (mem.startsWith(u8, arg, "--output-target=")) {
const next_arg = arg["--output-target=".len..];
if (mem.eql(u8, next_arg, "binary")) {
opt_out_fmt = .raw;
} else {
opt_out_fmt = std.meta.stringToEnum(std.Target.ObjectFormat, next_arg) orelse
fatal("invalid output format: '{s}'", .{next_arg});
}
} else if (mem.eql(u8, arg, "-j") or mem.eql(u8, arg, "--only-section")) {
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
only_section = args[i];
} else if (mem.eql(u8, arg, "--listen=-")) {
listen = true;
} else if (mem.startsWith(u8, arg, "--only-section=")) {
only_section = arg["--only-section=".len..];
} else if (mem.eql(u8, arg, "--pad-to")) {
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
pad_to = std.fmt.parseInt(u64, args[i], 0) catch |err| {
fatal("unable to parse: '{s}': {s}", .{ args[i], @errorName(err) });
};
} else if (mem.eql(u8, arg, "-g") or mem.eql(u8, arg, "--strip-debug")) {
strip_debug = true;
} else if (mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-all")) {
strip_all = true;
} else if (mem.eql(u8, arg, "--only-keep-debug")) {
only_keep_debug = true;
} else if (mem.eql(u8, arg, "--compress-debug-sections")) {
compress_debug_sections = true;
} else if (mem.startsWith(u8, arg, "--add-gnu-debuglink=")) {
opt_add_debuglink = arg["--add-gnu-debuglink=".len..];
} else if (mem.eql(u8, arg, "--add-gnu-debuglink")) {
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
opt_add_debuglink = args[i];
} else if (mem.startsWith(u8, arg, "--extract-to=")) {
opt_extract = arg["--extract-to=".len..];
} else if (mem.eql(u8, arg, "--extract-to")) {
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
opt_extract = args[i];
} else if (mem.eql(u8, arg, "--set-section-alignment")) {
i += 1;
if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg});
if (splitOption(args[i])) |split| {
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 <name>=<alignment>", .{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 = parseSectionFlags(split.second) };
} else {
fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{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 <name>=<file>", .{args[i]});
}
} else {
fatal("unrecognized argument: '{s}'", .{arg});
}
}
const input = opt_input orelse fatal("expected input parameter", .{});
const output = opt_output orelse fatal("expected output parameter", .{});
const input_file = Io.Dir.cwd().openFile(io, input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });
defer input_file.close(io);
const stat = input_file.stat(io) catch |err| fatal("failed to stat {s}: {t}", .{ input, err });
var in: File.Reader = .initSize(input_file, io, &input_buffer, stat.size);
const elf_hdr = std.elf.Header.read(&in.interface) catch |err| switch (err) {
error.ReadFailed => fatal("unable to read {s}: {t}", .{ input, in.err.? }),
else => |e| fatal("invalid elf file: {t}", .{e}),
};
const in_ofmt = .elf;
const out_fmt: std.Target.ObjectFormat = opt_out_fmt orelse ofmt: {
if (mem.endsWith(u8, output, ".hex") or std.mem.endsWith(u8, output, ".ihex")) {
break :ofmt .hex;
} else if (mem.endsWith(u8, output, ".bin")) {
break :ofmt .raw;
} else if (mem.endsWith(u8, output, ".elf")) {
break :ofmt .elf;
} else {
break :ofmt in_ofmt;
}
};
const permissions: Io.File.Permissions = if (out_fmt != .elf or only_keep_debug) .default_file else stat.permissions;
var output_file = try Io.Dir.cwd().createFile(io, output, .{ .permissions = permissions });
defer output_file.close(io);
var out = output_file.writer(io, &output_buffer);
switch (out_fmt) {
.hex, .raw => {
if (strip_debug or strip_all or only_keep_debug)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --strip", .{});
if (opt_extract != null)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --extract-to", .{});
if (add_section != null)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --add-section", .{});
if (set_section_alignment != null)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_alignment", .{});
if (set_section_flags != null)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});
try emitElf(arena, &in, &out, elf_hdr, .{
.ofmt = out_fmt,
.only_section = only_section,
.pad_to = pad_to,
});
},
.elf => {
if (elf_hdr.endian != builtin.target.cpu.arch.endian())
fatal("zig objcopy: ELF to ELF copying only supports native endian", .{});
if (elf_hdr.phoff == 0)
fatal("zig objcopy: ELF to ELF copying only supports programs", .{});
if (only_section) |_|
fatal("zig objcopy: ELF to ELF copying does not support --only-section", .{});
if (pad_to) |_|
fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{});
fatal("unimplemented", .{});
},
else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}),
}
try out.end();
if (listen) {
var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer);
var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
var server = try Server.init(.{
.in = &stdin_reader.interface,
.out = &stdout_writer.interface,
.zig_version = builtin.zig_version_string,
});
var seen_update = false;
while (true) {
const hdr = try server.receiveMessage();
switch (hdr.tag) {
.exit => {
return std.process.cleanExit(io);
},
.update => {
if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});
seen_update = true;
// only need to communicate that the process has finished.
// Use the empty error bundle to indicate that the update is done.
try server.serveErrorBundle(std.zig.ErrorBundle.empty);
},
else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),
}
}
}
return std.process.cleanExit(io);
}