commit 41f3b2c6175001fb9e8a0656ec2dec69dbdb5a38
parent e8bc95ca28685f8642767f92489c7b8b8da8781f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 16 Jul 2026 10:13:09 -0700
driver: accept conventional file and linker argument forms
Diffstat:
14 files changed, 306 insertions(+), 65 deletions(-)
diff --git a/driver/cmd/addr2line.c b/driver/cmd/addr2line.c
@@ -123,7 +123,7 @@ int driver_addr2line(int argc, char** argv) {
DriverEnv env;
A2lOpts opts;
DriverDwarfSym sym;
- int i, rc = 1, opened = 0;
+ int i, rc = 1, opened = 0, options = 1;
int stdin_addr_count = 0;
if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
@@ -136,6 +136,11 @@ int driver_addr2line(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) continue;
if (driver_streq(a, "-e")) {
if (i + 1 >= argc) {
driver_errf(A2L_TOOL, "-e requires a path");
@@ -183,9 +188,14 @@ int driver_addr2line(int argc, char** argv) {
}
/* scan for positional addresses */
+ options = 1;
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
- if (a[0] == '-' && a[1] != '\0') {
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (options && a[0] == '-' && a[1] != '\0') {
if (driver_streq(a, "-e")) {
++i;
continue;
diff --git a/driver/cmd/ar.c b/driver/cmd/ar.c
@@ -63,8 +63,8 @@ void driver_help_ar(void) {
"MODE is a string of one or more letters; exactly one operation "
"must\n"
"be selected and any number of modifiers may follow. The archive\n"
- "path and (optional) member list follow the mode. MODE has no\n"
- "leading dash: use `rcs`, not `-rcs`, in this release.\n"
+ "path and (optional) member list follow the mode. Both `rcs` and\n"
+ "the conventional `-rcs` spelling are accepted.\n"
"\n"
"OPERATIONS (mutually exclusive)\n"
" r Replace listed members in place; preserve unlisted; "
@@ -114,7 +114,7 @@ void driver_help_ar(void) {
" Archive and member names are file operands; archives are not read\n"
" from stdin. Operations t/x read the archive, x writes into the\n"
" current directory, and p writes selected member bytes to stdout.\n"
- " Prefix a leading-dash path with `./`; `--` is not accepted.\n"
+ " Use -- between MODE and a leading-dash archive path.\n"
"\n"
"EXAMPLES\n"
" kit ar rcs libfoo.a a.o b.o c.o\n"
@@ -688,6 +688,8 @@ int driver_ar(int argc, char** argv) {
int has_c = 0;
int has_s = 0;
int has_v = 0;
+ int argi = 1;
+ int member_start;
int i;
int rc;
@@ -696,13 +698,21 @@ int driver_ar(int argc, char** argv) {
return 0;
}
- if (argc < 3) {
+ if (driver_streq(argv[argi], "--")) ++argi;
+ if (argi >= argc) {
ar_usage();
return 2;
}
- mode = argv[1];
- archive_path = argv[2];
+ mode = argv[argi++];
+ if (mode[0] == '-' && mode[1] != '\0') ++mode;
+ if (argi < argc && driver_streq(argv[argi], "--")) ++argi;
+ if (argi >= argc) {
+ ar_usage();
+ return 2;
+ }
+ archive_path = argv[argi++];
+ member_start = argi;
for (i = 0; mode[i]; ++i) {
switch (mode[i]) {
@@ -763,19 +773,19 @@ int driver_ar(int argc, char** argv) {
driver_env_init(&env);
if (do_list) {
- if (argc != 3) {
+ if (member_start != argc) {
driver_errf(AR_TOOL, "t takes no member arguments");
driver_env_fini(&env);
return 2;
}
rc = ar_do_list(&env, archive_path, has_v);
} else if (do_extract) {
- rc = ar_do_extract(&env, archive_path, argc, argv, 3, has_v);
+ rc = ar_do_extract(&env, archive_path, argc, argv, member_start, has_v);
} else if (do_print) {
- rc = ar_do_print(&env, archive_path, argc, argv, 3, has_v);
+ rc = ar_do_print(&env, archive_path, argc, argv, member_start, has_v);
} else {
- rc = ar_do_write(&env, archive_path, argc - 3, argv + 3, has_r, has_c,
- has_s, has_v);
+ rc = ar_do_write(&env, archive_path, argc - member_start,
+ argv + member_start, has_r, has_c, has_s, has_v);
}
driver_env_fini(&env);
diff --git a/driver/cmd/as.c b/driver/cmd/as.c
@@ -37,6 +37,7 @@ void driver_help_as(void) {
"USAGE\n"
" kit as [options] -o OUT.o INPUT.s\n"
" kit as [options] -o OUT.o INPUT.S\n"
+ " kit as [options] -o OUT.o - (read raw assembly from stdin)\n"
"\n"
"DESCRIPTION\n"
" Reads a single text source written in a GAS subset (AT&T syntax "
@@ -64,18 +65,17 @@ void driver_help_as(void) {
" Canonical assembler examples are aarch64-none-elf,\n"
" x86_64-linux-gnu, and riscv64-none-elf. The release also accepts\n"
" the corresponding hosted/freestanding triples documented by\n"
- " `kit cc --help`. A literal `-` is treated as a filename, not\n"
- " stdin, in this release. Write piped assembly to a temporary .s\n"
- " file first. Spell a leading-dash path as ./-name.s.\n"
+ " `kit cc --help`. A literal `-` reads raw (non-preprocessed)\n"
+ " assembly from stdin and uses <stdin> in diagnostics. Use --\n"
+ " before a leading-dash path.\n"
"\n"
"EXAMPLES\n"
" kit as -target aarch64-none-elf -g -o start.o start.s\n"
" kit as -target x86_64-linux-gnu -DDEBUG=1 -I include \\\n"
" -o entry.o entry.S\n"
"\n"
- " tmp=\"${TMPDIR:-/tmp}/kit-stdin.s\"\n"
- " printf '.text\\n.globl entry\\nentry:\\n ret\\n' > \"$tmp\"\n"
- " kit as -target x86_64-linux-gnu -o entry.o \"$tmp\"\n"
+ " printf '.text\\n.globl entry\\nentry:\\n ret\\n' | \\\n"
+ " kit as -target x86_64-linux-gnu -o entry.o -\n"
"\n"
"EXIT CODES\n"
" 0 success 1 assemble error 2 bad "
@@ -86,6 +86,7 @@ void driver_help_as(void) {
static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
DriverCflags* cf, DriverTargetFeatures* tf) {
int i;
+ int options = 1;
o->target = driver_host_target();
@@ -93,6 +94,19 @@ static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
const char* a = argv[i];
int r;
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options || driver_streq(a, "-")) {
+ if (o->source) {
+ driver_errf(AS_TOOL, "multiple inputs not supported");
+ return 1;
+ }
+ o->source = a;
+ continue;
+ }
+
r = driver_cflags_try_consume(cf, env, AS_TOOL, argc, argv, &i);
if (r < 0) return 1;
if (r > 0) continue;
@@ -117,8 +131,7 @@ static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
return 1;
}
if (driver_target_from_triple(argv[i], &o->target) != 0) {
- driver_errf(AS_TOOL, "unrecognized target: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
+ driver_err_unknown_target(AS_TOOL, argv[i]);
return 1;
}
continue;
@@ -168,6 +181,8 @@ int driver_as(int argc, char** argv) {
KitWriter* writer = NULL;
KitWriter* pp_writer = NULL;
KitFileData src = {0};
+ uint8_t* stdin_data = NULL;
+ size_t stdin_len = 0;
KitSlice input;
KitSlice asm_input;
KitAsmCompileOptions copts;
@@ -203,12 +218,23 @@ int driver_as(int argc, char** argv) {
ctx = driver_env_to_context(&env);
- if (ctx.file_io->read_all(ctx.file_io->user, o.source, &src) != KIT_OK) {
- driver_errf(AS_TOOL, "failed to read: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(o.source)));
- goto out;
+ if (driver_streq(o.source, "-")) {
+ if (!driver_read_stdin(&env, &stdin_data, &stdin_len)) {
+ driver_errf(AS_TOOL, "failed to read stdin");
+ goto out;
+ }
+ input.data = stdin_data;
+ input.len = stdin_len;
+ } else {
+ if (ctx.file_io->read_all(ctx.file_io->user, o.source, &src) != KIT_OK) {
+ driver_errf(AS_TOOL, "failed to read: %.*s",
+ KIT_SLICE_ARG(kit_slice_cstr(o.source)));
+ goto out;
+ }
+ loaded = 1;
+ input.data = src.data;
+ input.len = src.size;
}
- loaded = 1;
if (ctx.file_io->open_writer(ctx.file_io->user, o.output_path, &writer) !=
KIT_OK) {
@@ -226,8 +252,6 @@ int driver_as(int argc, char** argv) {
copts = zero;
copts.code.debug_info = o.debug_info;
- input.data = src.data;
- input.len = src.size;
asm_input = input;
if (driver_has_suffix(o.source, ".S")) {
@@ -260,7 +284,8 @@ int driver_as(int argc, char** argv) {
sopts.compile.diagnostics = copts.diagnostics;
sopts.compile.language_options = &copts;
memset(&sin, 0, sizeof(sin));
- sin.name = kit_slice_cstr(o.source);
+ sin.name =
+ kit_slice_cstr(driver_streq(o.source, "-") ? "<stdin>" : o.source);
sin.bytes = asm_input;
sin.lang = KIT_LANG_ASM;
st = kit_compile_session_new(compiler, &sopts, &session);
@@ -277,6 +302,7 @@ out:
if (pp_writer) kit_writer_close(pp_writer);
if (writer) kit_writer_close(writer);
if (loaded) ctx.file_io->release(ctx.file_io->user, &src);
+ if (stdin_data) driver_free(&env, stdin_data, stdin_len);
driver_target_features_fini(&tf, &env);
driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
diff --git a/driver/cmd/compress.c b/driver/cmd/compress.c
@@ -64,6 +64,19 @@ static int compress_parse_format(const char* s, KitCompressFormat* out) {
return 1;
}
+static void compress_unknown_format(const char* tool, const char* value) {
+ const char* const formats[] = {"gzip", "gz", "lz4"};
+ DriverSuggestion suggestions[3];
+ size_t n = driver_suggest_values(value, formats,
+ sizeof formats / sizeof formats[0],
+ suggestions, 3);
+ if (n)
+ driver_errf(tool, "unknown format: %s; did you mean '%s'?", value,
+ suggestions[0].value);
+ else
+ driver_errf(tool, "unknown format: %s (use gzip or lz4)", value);
+}
+
/* gzip/lz4-style flags accepted (as no-ops) under an alias so the tool works
* as a drop-in. kit always streams stdin/-o to stdout and never mutates the
* input in place, so -c/--stdout, -k/--keep and -f/--force have nothing to do;
@@ -118,7 +131,7 @@ static void compress_help(const CompressPersona* persona) {
" describes default direction and accepted compatibility flags.\n"
"\n"
"PATHS\n"
- " Bare -- is not accepted; spell a leading-dash file as ./-name.\n"
+ " Use -- before a leading-dash file name.\n"
"\n"
"EXAMPLES\n"
" kit compress -z gzip -o data.gz data.txt\n"
@@ -151,7 +164,7 @@ static void compress_help(const CompressPersona* persona) {
" -z/--format is rejected because gzip fixes the container.\n"
"\n"
"PATHS\n"
- " Bare -- is not accepted; spell a leading-dash file as ./-name.\n"
+ " Use -- before a leading-dash file name.\n"
"\n"
"EXAMPLES\n"
" gzip -o data.gz data.txt\n"
@@ -180,7 +193,7 @@ static void compress_help(const CompressPersona* persona) {
" -z/--format is rejected because gunzip fixes gzip input.\n"
"\n"
"PATHS\n"
- " Bare -- is not accepted; spell a leading-dash file as ./-name.\n"
+ " Use -- before a leading-dash file name.\n"
"\n"
"EXAMPLES\n"
" gunzip -o data.txt data.gz\n"
@@ -209,7 +222,7 @@ static void compress_help(const CompressPersona* persona) {
" -z/--format is rejected because the container is fixed.\n"
"\n"
"PATHS\n"
- " Bare -- is not accepted; spell a leading-dash file as ./-name.\n"
+ " Use -- before a leading-dash file name.\n"
"\n"
"EXAMPLES\n"
" %s -o data.lz4 data.txt\n"
@@ -243,7 +256,7 @@ static int compress_main(int argc, char** argv,
DriverLoad ld = {0};
uint8_t* sbuf = NULL;
size_t sbuf_len = 0;
- int loaded = 0, owned_writer = 0, i, rc = 2;
+ int loaded = 0, owned_writer = 0, i, rc = 2, options = 1;
KitCompressFormat fmt;
if (driver_argv_wants_help(argc, argv, 1)) {
@@ -262,27 +275,37 @@ static int compress_main(int argc, char** argv,
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
- if (driver_streq(a, "-d") ||
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (options && (driver_streq(a, "-d") ||
(persona->compat && (driver_streq(a, "--decompress") ||
- driver_streq(a, "--uncompress")))) {
+ driver_streq(a, "--uncompress"))))) {
o.decompress = 1;
continue;
}
- if (driver_streq(a, "-z") || driver_streq(a, "--format")) {
+ if (options &&
+ (driver_streq(a, "-z") || driver_streq(a, "--format"))) {
if (persona->locked_format) {
driver_errf(persona->name, "-z is not accepted; %s always uses %s",
persona->name,
persona->format == KIT_COMPRESS_GZIP ? "gzip" : "lz4");
goto done;
}
- if (i + 1 >= argc || compress_parse_format(argv[++i], &o.format) != 0) {
- driver_errf(persona->name, "-z requires gzip or lz4");
+ if (i + 1 >= argc) {
+ driver_errf(persona->name, "%s requires gzip or lz4", a);
+ goto done;
+ }
+ ++i;
+ if (compress_parse_format(argv[i], &o.format) != 0) {
+ compress_unknown_format(persona->name, argv[i]);
goto done;
}
o.have_format = 1;
continue;
}
- if (driver_streq(a, "-o")) {
+ if (options && driver_streq(a, "-o")) {
if (i + 1 >= argc) {
driver_errf(persona->name, "-o requires a file path");
goto done;
@@ -298,9 +321,21 @@ static int compress_main(int argc, char** argv,
o.seen_input = 1;
continue;
}
- if (persona->compat && compress_compat_noop(a)) continue;
- if (a[0] == '-' && a[1] != '\0') {
- driver_errf(persona->name, "unknown option: %s", a);
+ if (options && persona->compat && compress_compat_noop(a)) continue;
+ if (options && a[0] == '-' && a[1] != '\0') {
+ const char* const valid[] = {
+ "-d", "--decompress", "--uncompress", "-z", "--format",
+ "-o", "-h", "--help", "--version"};
+ DriverSuggestion suggestions[3];
+ size_t n = driver_suggest_values(a, valid,
+ sizeof valid / sizeof valid[0],
+ suggestions, 3);
+ if (n)
+ driver_errf(persona->name,
+ "unknown option: %s; did you mean '%s'?", a,
+ suggestions[0].value);
+ else
+ driver_errf(persona->name, "unknown option: %s", a);
goto done;
}
if (o.seen_input) {
diff --git a/driver/cmd/disas.c b/driver/cmd/disas.c
@@ -49,8 +49,8 @@ void driver_help_disas(void) {
"\n"
"INPUT AND LIMITATIONS\n"
" FILE is raw code, not an object file; use kit objdump -d for\n"
- " objects. Bare -- is not accepted, so spell a leading-dash file\n"
- " as ./-code.bin. A trailing partial fixed-width instruction is\n"
+ " objects. Use -- before a leading-dash file name. A trailing\n"
+ " partial fixed-width instruction is\n"
" rendered as `(truncated)` and currently still returns success.\n"
"\n"
"EXAMPLES\n"
@@ -151,7 +151,7 @@ int driver_disas(int argc, char** argv) {
size_t sbuf_len = 0;
uint8_t* hexbuf = NULL;
size_t hexbuf_len = 0;
- int loaded = 0, npos = 0, rc = 2;
+ int loaded = 0, npos = 0, rc = 2, options = 1;
int i;
if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
@@ -171,13 +171,27 @@ int driver_disas(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) {
+ if (npos == 0)
+ o.in = a;
+ else {
+ driver_errf(DISAS_TOOL, "too many operands: %s", a);
+ goto done;
+ }
+ ++npos;
+ continue;
+ }
if (driver_streq(a, "-target")) {
if (i + 1 >= argc) {
driver_errf(DISAS_TOOL, "-target requires an argument");
goto done;
}
if (driver_target_from_triple(argv[++i], &o.target) != 0) {
- driver_errf(DISAS_TOOL, "unrecognized target: %s", argv[i]);
+ driver_err_unknown_target(DISAS_TOOL, argv[i]);
goto done;
}
continue;
diff --git a/driver/cmd/mc.c b/driver/cmd/mc.c
@@ -192,13 +192,17 @@ int driver_mc(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (driver_streq(a, "--")) {
+ if (i + 1 < argc) first_pos = i + 1;
+ break;
+ }
if (driver_streq(a, "-target")) {
if (i + 1 >= argc) {
driver_errf(MC_TOOL, "-target requires an argument");
goto done;
}
if (driver_target_from_triple(argv[++i], &o.target) != 0) {
- driver_errf(MC_TOOL, "unrecognized target: %s", argv[i]);
+ driver_err_unknown_target(MC_TOOL, argv[i]);
goto done;
}
continue;
diff --git a/driver/cmd/nm.c b/driver/cmd/nm.c
@@ -291,7 +291,7 @@ int driver_nm(int argc, char** argv) {
NmSym* syms = NULL;
uint32_t nsyms = 0, cap = 0;
int ptr_digits = 8;
- int i, rc = 1, any_input = 0;
+ int i, rc = 1, any_input = 0, options = 1;
if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
driver_help_nm();
@@ -304,6 +304,11 @@ int driver_nm(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) goto nm_input;
if (driver_streq(a, "-a") || driver_streq(a, "--debug-syms")) {
opts.debug_syms = 1;
continue;
@@ -345,6 +350,7 @@ int driver_nm(int argc, char** argv) {
rc = 2;
goto done;
}
+ nm_input:
{
const char* path = a;
DriverLoad ld = {0};
diff --git a/driver/cmd/objdump.c b/driver/cmd/objdump.c
@@ -1365,6 +1365,7 @@ int driver_objdump(int argc, char** argv) {
int rc = 0;
int saw_input = 0;
int saw_op = 0;
+ int options = 1;
KitContext ctx;
KitDisasmContext dctx;
KitDisasmContext* dctx_p = NULL;
@@ -1382,6 +1383,11 @@ int driver_objdump(int argc, char** argv) {
/* First pass: parse flags. */
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) continue;
if (a[0] != '-' || a[1] == '\0') continue;
if (driver_streq(a, "-j")) {
if (i + 1 >= argc) {
@@ -1434,13 +1440,19 @@ int driver_objdump(int argc, char** argv) {
}
/* Second pass: process inputs. */
+ options = 1;
for (i = 1; i < argc && rc == 0; ++i) {
const char* a = argv[i];
KitFileData fd = {0};
KitSlice input;
KitBinFmt bin;
- if (a[0] == '-' && a[1] != '\0') {
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+
+ if (options && a[0] == '-' && a[1] != '\0') {
if (driver_streq(a, "-j")) ++i;
continue;
}
diff --git a/driver/cmd/strings.c b/driver/cmd/strings.c
@@ -101,14 +101,13 @@ void driver_help_strings(void) {
" print the input file name before each string\n"
" -h, --help show this help\n"
"\n"
- " Prefix a leading-dash file name with `./` (for example\n"
- " `./-firmware.bin`); `--` is not accepted in this release.\n"
+ " Use -- before a leading-dash file name.\n"
"\n"
"EXAMPLES\n"
" kit strings -n 8 firmware.bin\n"
" kit strings -t x -f app.o libfoo.a\n"
" kit strings -n 6 < firmware.bin\n"
- " kit strings ./-firmware.bin\n"
+ " kit strings -- -firmware.bin\n"
"\n"
"EXIT CODES\n"
" 0 success 1 I/O error 2 bad usage\n")));
@@ -131,7 +130,7 @@ static int strings_parse_min(const char* s, size_t* out) {
int driver_strings(int argc, char** argv) {
DriverEnv env;
StringsOpts opts;
- int i, rc = 1, any_input = 0;
+ int i, rc = 1, any_input = 0, options = 1;
if (driver_argv_wants_help(argc, argv, 1)) {
driver_help_strings();
@@ -146,6 +145,14 @@ int driver_strings(int argc, char** argv) {
/* First pass: options. */
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) {
+ any_input = 1;
+ continue;
+ }
if (driver_streq(a, "-n") || driver_streq(a, "--bytes")) {
if (i + 1 >= argc || strings_parse_min(argv[++i], &opts.min_len) != 0) {
driver_errf(STRINGS_TOOL, "option %s requires a positive integer", a);
@@ -224,17 +231,23 @@ int driver_strings(int argc, char** argv) {
}
/* Second pass: inputs, in argv order. */
+ options = 1;
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
/* Skip the options consumed above (and their values). */
- if (driver_streq(a, "-n") || driver_streq(a, "--bytes") ||
- driver_streq(a, "-t")) {
+ if (options && (driver_streq(a, "-n") ||
+ driver_streq(a, "--bytes") || driver_streq(a, "-t"))) {
++i;
continue;
}
- if (strncmp(a, "--bytes=", 8) == 0 || driver_streq(a, "-f") ||
- driver_streq(a, "--print-file-name") ||
- (a[0] == '-' && a[1] >= '0' && a[1] <= '9')) {
+ if (options &&
+ (strncmp(a, "--bytes=", 8) == 0 || driver_streq(a, "-f") ||
+ driver_streq(a, "--print-file-name") ||
+ (a[0] == '-' && a[1] >= '0' && a[1] <= '9'))) {
continue;
}
if (driver_streq(a, "-")) {
diff --git a/driver/cmd/xxd.c b/driver/cmd/xxd.c
@@ -117,8 +117,7 @@ void driver_help_xxd(void) {
"NOTE\n"
" -r reconstructs contiguous data; leading offsets are read for\n"
" context but not used to seek/pad sparse output.\n"
- " Bare -- is not accepted in this release. Prefix a leading-dash\n"
- " input with ./, for example ./-payload.bin.\n"
+ " Use -- before a leading-dash input.\n"
"\n"
"EXAMPLES\n"
" kit xxd firmware.bin\n"
@@ -276,7 +275,7 @@ int driver_xxd(int argc, char** argv) {
DriverLoad ld = {0};
uint8_t* sbuf = NULL;
size_t sbuf_len = 0;
- int loaded = 0, npos = 0, rc = 2, owned_writer = 0;
+ int loaded = 0, npos = 0, rc = 2, owned_writer = 0, options = 1;
int i;
size_t cols, group;
const char* hx;
@@ -293,6 +292,22 @@ int driver_xxd(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ if (options && driver_streq(a, "--")) {
+ options = 0;
+ continue;
+ }
+ if (!options) {
+ if (npos == 0)
+ o.in = a;
+ else if (npos == 1 && !o.out)
+ o.out = a;
+ else {
+ driver_errf(XXD_TOOL, "too many operands: %s", a);
+ goto done;
+ }
+ ++npos;
+ continue;
+ }
if (driver_streq(a, "-r")) {
o.reverse = 1;
continue;
diff --git a/driver/lib/link_flags.c b/driver/lib/link_flags.c
@@ -188,6 +188,38 @@ static int lf_record_interp(DriverLinkFlags* lf, const char* s, size_t n) {
return 0;
}
+int driver_link_flags_record_entry(DriverLinkFlags* lf, const char* val,
+ size_t n) {
+ char* buf;
+ if (!val || n == 0) {
+ driver_errf(lf->tool, "--entry requires a non-empty symbol");
+ return 1;
+ }
+ buf = lf_dup_owned(lf, val, n);
+ if (!buf) {
+ driver_errf(lf->tool, "out of memory");
+ return 1;
+ }
+ lf->entry = buf;
+ return 0;
+}
+
+int driver_link_flags_record_script(DriverLinkFlags* lf, const char* val,
+ size_t n) {
+ char* buf;
+ if (!val || n == 0) {
+ driver_errf(lf->tool, "--script requires a non-empty path");
+ return 1;
+ }
+ buf = lf_dup_owned(lf, val, n);
+ if (!buf) {
+ driver_errf(lf->tool, "out of memory");
+ return 1;
+ }
+ lf->linker_script = buf;
+ return 0;
+}
+
int driver_link_flags_record_map(DriverLinkFlags* lf, const char* val,
size_t n) {
char* buf;
@@ -557,6 +589,8 @@ int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
int expect_section_start = 0;
int expect_cref = 0;
int expect_orphan = 0;
+ int expect_entry = 0;
+ int expect_script = 0;
while (*p) {
const char* tok = p;
size_t n = 0;
@@ -565,7 +599,8 @@ int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
if (expect_rpath || expect_soname || expect_interp || expect_subsystem ||
expect_z || expect_map || expect_symbols || expect_ttext ||
- expect_defsym || expect_section_start || expect_cref || expect_orphan) {
+ expect_defsym || expect_section_start || expect_cref || expect_orphan ||
+ expect_entry || expect_script) {
int rc = 0;
if (expect_rpath)
rc = lf_record_rpath(lf, tok, n);
@@ -589,6 +624,10 @@ int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
rc = driver_link_flags_record_cref(lf, tok, n);
else if (expect_orphan)
rc = driver_link_flags_record_orphan_handling(lf, tok, n);
+ else if (expect_entry)
+ rc = driver_link_flags_record_entry(lf, tok, n);
+ else if (expect_script)
+ rc = driver_link_flags_record_script(lf, tok, n);
else if (expect_ttext) {
char* buf = lf_dup_owned(lf, tok, n);
if (!buf) {
@@ -601,7 +640,35 @@ int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
expect_rpath = expect_soname = expect_interp = expect_subsystem =
expect_z = expect_map = expect_symbols = expect_ttext =
expect_defsym = expect_section_start = expect_cref =
- expect_orphan = 0;
+ expect_orphan = expect_entry = expect_script = 0;
+ continue;
+ }
+
+ if (lf_tok_eq(tok, n, "-e") || lf_tok_eq(tok, n, "--entry")) {
+ expect_entry = 1;
+ continue;
+ }
+ if (lf_tok_prefix(tok, n, "--entry=")) {
+ if (driver_link_flags_record_entry(lf, tok + 8, n - 8u) != 0) return 1;
+ continue;
+ }
+ if (n > 2 && tok[0] == '-' && tok[1] == 'e') {
+ if (driver_link_flags_record_entry(lf, tok + 2, n - 2u) != 0) return 1;
+ continue;
+ }
+ if (lf_tok_eq(tok, n, "-T") || lf_tok_eq(tok, n, "--script")) {
+ expect_script = 1;
+ continue;
+ }
+ if (lf_tok_prefix(tok, n, "--script=")) {
+ if (driver_link_flags_record_script(lf, tok + 9, n - 9u) != 0) return 1;
+ continue;
+ }
+ if (n > 2 && tok[0] == '-' && tok[1] == 'T' &&
+ !lf_tok_prefix(tok, n, "-Ttext") &&
+ !lf_tok_prefix(tok, n, "-Tdata") &&
+ !lf_tok_prefix(tok, n, "-Tbss")) {
+ if (driver_link_flags_record_script(lf, tok + 2, n - 2u) != 0) return 1;
continue;
}
@@ -829,7 +896,8 @@ int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
}
if (expect_rpath || expect_soname || expect_interp || expect_subsystem ||
expect_z || expect_map || expect_symbols || expect_ttext ||
- expect_defsym || expect_section_start || expect_cref || expect_orphan) {
+ expect_defsym || expect_section_start || expect_cref || expect_orphan ||
+ expect_entry || expect_script) {
driver_errf(lf->tool, "-Wl option requires another comma argument");
return 1;
}
diff --git a/driver/lib/link_flags.h b/driver/lib/link_flags.h
@@ -69,6 +69,10 @@ int driver_link_flags_record_symbols(DriverLinkFlags* lf, const char* val,
int driver_link_flags_record_symbols_format(DriverLinkFlags* lf,
const char* val, size_t n);
int driver_link_flags_record_text_base(DriverLinkFlags* lf, const char* val);
+int driver_link_flags_record_entry(DriverLinkFlags* lf, const char* val,
+ size_t n);
+int driver_link_flags_record_script(DriverLinkFlags* lf, const char* val,
+ size_t n);
/* --defsym NAME=EXPR (literal hex/dec or alias-symbol form). */
int driver_link_flags_record_defsym(DriverLinkFlags* lf, const char* val,
size_t n);
diff --git a/test/ar/cases/08-conventional-dash-and-alias.expected b/test/ar/cases/08-conventional-dash-and-alias.expected
@@ -0,0 +1,4 @@
+== direct -rcs ==
+-member.o
+== installed rcs ==
+-member.o
diff --git a/test/ar/cases/08-conventional-dash-and-alias.sh b/test/ar/cases/08-conventional-dash-and-alias.sh
@@ -0,0 +1,20 @@
+# Conventional dash-prefixed mode, `--` archive delimiter, installed argv[0]
+# dispatch, and leading-dash operands inside directories containing spaces.
+mkdir 'dash path' 'tool aliases'
+printf 'member bytes\n' > 'dash path/-member.o'
+"$KIT" install "$PWD/tool aliases" ar >/dev/null
+ar_alias="$PWD/tool aliases/ar"
+
+echo '== direct -rcs =='
+(
+ cd 'dash path'
+ "$KIT" ar -rcs -- -direct.a -member.o
+ "$KIT" ar t -- -direct.a
+)
+
+echo '== installed rcs =='
+(
+ cd 'dash path'
+ "$ar_alias" rcs -- -alias.a -member.o
+ "$ar_alias" t -- -alias.a
+)