kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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:
Mdriver/cmd/addr2line.c | 14++++++++++++--
Mdriver/cmd/ar.c | 32+++++++++++++++++++++-----------
Mdriver/cmd/as.c | 58++++++++++++++++++++++++++++++++++++++++++----------------
Mdriver/cmd/compress.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mdriver/cmd/disas.c | 22++++++++++++++++++----
Mdriver/cmd/mc.c | 6+++++-
Mdriver/cmd/nm.c | 8+++++++-
Mdriver/cmd/objdump.c | 14+++++++++++++-
Mdriver/cmd/strings.c | 31++++++++++++++++++++++---------
Mdriver/cmd/xxd.c | 21++++++++++++++++++---
Mdriver/lib/link_flags.c | 74+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdriver/lib/link_flags.h | 4++++
Atest/ar/cases/08-conventional-dash-and-alias.expected | 4++++
Atest/ar/cases/08-conventional-dash-and-alias.sh | 20++++++++++++++++++++
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 +)