commit 923c2ef63261ed6e24eee8c65c9ff7f5153345e5
parent ce021f13c697ea50f184ce1aeef44bef4b6e9a0e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 11 May 2026 17:18:07 -0700
Preprocess .S inputs in assembler driver
Diffstat:
| M | driver/as.c | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
1 file changed, 55 insertions(+), 8 deletions(-)
diff --git a/driver/as.c b/driver/as.c
@@ -1,11 +1,12 @@
#include <stdint.h>
+#include "cflags.h"
#include "driver.h"
/* `cfree as` — standalone assembler. Reads a single text source, writes a
* relocatable object via cfree_compile_obj_emit with the input tagged
- * CFREE_LANG_ASM. The accepted input is a GAS subset (AT&T syntax on x86);
- * see <cfree.h>. */
+ * CFREE_LANG_ASM. `.S` inputs are preprocessed first; `.s` inputs are not.
+ * The accepted input is a GAS subset (AT&T syntax on x86); see <cfree.h>. */
#define AS_TOOL "as"
@@ -18,7 +19,7 @@ typedef struct AsOptions {
static void as_usage(void) {
driver_errf(AS_TOOL, "%s",
- "usage: cfree as [-g] [-target TRIPLE] -o out.o input.s\n"
+ "usage: cfree as [-g] [-target TRIPLE] -o out.o input.{s,S}\n"
" cfree as --help for full option reference");
}
@@ -29,16 +30,22 @@ void driver_help_as(void) {
"\n"
"USAGE\n"
" cfree as [options] -o OUT.o INPUT.s\n"
+ " cfree as [options] -o OUT.o INPUT.S\n"
"\n"
"DESCRIPTION\n"
" Reads a single text source written in a GAS subset (AT&T syntax on\n"
" x86, standard mnemonics on aarch64/riscv64) and writes a relocatable\n"
- " object via the same back-end the C compiler emits to. Exactly one\n"
- " positional input is required; -o is required.\n"
+ " object via the same back-end the C compiler emits to. INPUT.S is run\n"
+ " through the C preprocessor first; INPUT.s is assembled directly.\n"
+ " Exactly one positional input is required; -o is required.\n"
"\n"
"OPTIONS\n"
" -o PATH Output object path (required)\n"
" -g Emit DWARF debug info from .file/.loc directives\n"
+ " -I DIR, -IDIR Add a user include directory for INPUT.S\n"
+ " -isystem DIR Add a system include directory for INPUT.S\n"
+ " -D NAME[=VALUE] Define a preprocessor macro for INPUT.S\n"
+ " -U NAME Undefine a preprocessor macro for INPUT.S\n"
" -target TRIPLE Cross-assemble target. See `cfree cc --help` for "
"the\n"
" full list of recognized arches and OSes. Default:\n"
@@ -50,13 +57,19 @@ void driver_help_as(void) {
}
/* Returns 0 on success; non-zero on bad args (already reported). */
-static int as_parse(int argc, char** argv, AsOptions* o) {
+static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
+ DriverCflags* cf) {
int i;
o->target = driver_host_target();
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
+ int r;
+
+ r = driver_cflags_try_consume(cf, env, AS_TOOL, argc, argv, &i);
+ if (r < 0) return 1;
+ if (r > 0) continue;
if (driver_streq(a, "-g")) {
o->debug_info = 1;
@@ -111,13 +124,19 @@ static int as_parse(int argc, char** argv, AsOptions* o) {
int driver_as(int argc, char** argv) {
DriverEnv env;
AsOptions o = {0};
+ DriverCflags cf = {0};
CfreeEnv cenv;
+ CfreePpOptions pp;
CfreeCompiler* compiler = NULL;
CfreeWriter* writer = NULL;
+ CfreeWriter* pp_writer = NULL;
CfreeFileData src = {0};
CfreeBytesInput input;
+ CfreeBytesInput asm_input;
CfreeCompileOptions copts;
CfreeCompileOptions zero = {0};
+ const uint8_t* pp_data;
+ size_t pp_len;
int rc = 1;
int loaded = 0;
@@ -128,10 +147,18 @@ int driver_as(int argc, char** argv) {
driver_env_init(&env);
- if (as_parse(argc, argv, &o) != 0) {
+ if (driver_cflags_init(&cf, &env, argc) != 0) {
+ driver_errf(AS_TOOL, "out of memory");
+ driver_env_fini(&env);
+ return 2;
+ }
+
+ if (as_parse(argc, argv, &o, &env, &cf) != 0) {
+ driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return 2;
}
+ driver_cflags_fill_pp(&cf, &pp);
cenv = driver_env_to_cfree(&env);
@@ -160,13 +187,33 @@ int driver_as(int argc, char** argv) {
input.data = src.data;
input.len = src.size;
input.lang = CFREE_LANG_ASM;
+ asm_input = input;
+
+ if (driver_has_suffix(o.source, ".S")) {
+ pp_writer = cfree_writer_mem(cenv.heap);
+ if (!pp_writer) {
+ driver_errf(AS_TOOL, "out of memory");
+ goto out;
+ }
+ if (cfree_preprocess(compiler, &pp, &input, pp_writer) != 0) goto out;
+ if (cfree_writer_error(pp_writer)) {
+ driver_errf(AS_TOOL, "failed to preprocess: %s", o.source);
+ goto out;
+ }
+ pp_data = cfree_writer_mem_bytes(pp_writer, &pp_len);
+ asm_input.data = pp_data;
+ asm_input.len = pp_len;
+ asm_input.lang = CFREE_LANG_ASM;
+ }
- rc = cfree_compile_obj_emit(compiler, &copts, &input, writer);
+ rc = cfree_compile_obj_emit(compiler, &copts, &asm_input, writer);
out:
if (compiler) driver_compiler_free(compiler);
+ if (pp_writer) cfree_writer_close(pp_writer);
if (writer) cfree_writer_close(writer);
if (loaded) cenv.file_io->release(cenv.file_io->user, &src);
+ driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return rc;
}