kit

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

as.c (8168B)


      1 #include <kit/compile.h>
      2 #include <kit/core.h>
      3 #include <kit/preprocess.h>
      4 #include <stdint.h>
      5 #include <string.h>
      6 
      7 #include "cflags.h"
      8 #include "driver.h"
      9 
     10 /* `kit as` — standalone assembler. Reads a single text source, writes a
     11  * relocatable object via a KitCompileSession. `.S` inputs are
     12  * preprocessed first via kit_cpp_preprocess; `.s` inputs are not. The
     13  * accepted input is a GAS subset (AT&T syntax on x86). */
     14 
     15 #define AS_TOOL "as"
     16 
     17 typedef struct AsOptions {
     18   int debug_info;          /* -g                       */
     19   const char* output_path; /* -o                       */
     20   const char* source;      /* single positional input  */
     21   KitTargetSpec target;    /* -target TRIPLE; host default */
     22 } AsOptions;
     23 
     24 static void as_usage(void) {
     25   driver_errf(AS_TOOL, "%.*s",
     26               KIT_SLICE_ARG(KIT_SLICE_LIT(
     27                   "usage: kit as [-g] [-target TRIPLE] -o out.o input.{s,S}\n"
     28                   "       kit as --help    for full option reference")));
     29 }
     30 
     31 void driver_help_as(void) {
     32   driver_printf(
     33       "%.*s",
     34       KIT_SLICE_ARG(KIT_SLICE_LIT(
     35           "kit as — standalone assembler\n"
     36           "\n"
     37           "USAGE\n"
     38           "  kit as [options] -o OUT.o INPUT.s\n"
     39           "  kit as [options] -o OUT.o INPUT.S\n"
     40           "\n"
     41           "DESCRIPTION\n"
     42           "  Reads a single text source written in a GAS subset (AT&T syntax "
     43           "on\n"
     44           "  x86, standard mnemonics on aarch64/riscv64) and writes a "
     45           "relocatable\n"
     46           "  object via the same back-end the C compiler emits to. INPUT.S is "
     47           "run\n"
     48           "  through the C preprocessor first; INPUT.s is assembled directly.\n"
     49           "  Exactly one positional input is required; -o is required.\n"
     50           "\n"
     51           "OPTIONS\n"
     52           "  -o PATH           Output object path (required)\n"
     53           "  -g                Emit DWARF debug info from .file/.loc "
     54           "directives\n"
     55           "  -I DIR, -IDIR     Add a user include directory for INPUT.S\n"
     56           "  -isystem DIR      Add a system include directory for INPUT.S\n"
     57           "  -D NAME[=VALUE]   Define a preprocessor macro for INPUT.S\n"
     58           "  -U NAME           Undefine a preprocessor macro for INPUT.S\n"
     59           "  -target TRIPLE    Cross-assemble target. See `kit cc --help` "
     60           "for "
     61           "the\n"
     62           "                    full list of recognized arches and OSes. "
     63           "Default:\n"
     64           "                    the host target.\n"
     65           "  -h, --help        Show this help and exit\n"
     66           "\n"
     67           "EXIT CODES\n"
     68           "  0   success           1   assemble error           2   bad "
     69           "usage\n")));
     70 }
     71 
     72 /* Returns 0 on success; non-zero on bad args (already reported). */
     73 static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
     74                     DriverCflags* cf, DriverTargetFeatures* tf) {
     75   int i;
     76 
     77   o->target = driver_host_target();
     78 
     79   for (i = 1; i < argc; ++i) {
     80     const char* a = argv[i];
     81     int r;
     82 
     83     r = driver_cflags_try_consume(cf, env, AS_TOOL, argc, argv, &i);
     84     if (r < 0) return 1;
     85     if (r > 0) continue;
     86 
     87     if (driver_streq(a, "-g")) {
     88       o->debug_info = 1;
     89       continue;
     90     }
     91 
     92     if (driver_streq(a, "-o")) {
     93       if (++i >= argc) {
     94         driver_errf(AS_TOOL, "-o requires an argument");
     95         return 1;
     96       }
     97       o->output_path = argv[i];
     98       continue;
     99     }
    100 
    101     if (driver_streq(a, "-target")) {
    102       if (++i >= argc) {
    103         driver_errf(AS_TOOL, "-target requires an argument");
    104         return 1;
    105       }
    106       if (driver_target_from_triple(argv[i], &o->target) != 0) {
    107         driver_errf(AS_TOOL, "unrecognized target: %.*s",
    108                     KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
    109         return 1;
    110       }
    111       continue;
    112     }
    113 
    114     {
    115       int tr =
    116           driver_target_features_try_consume(tf, env, AS_TOOL, argc, argv, &i);
    117       if (tr < 0) return 1;
    118       if (tr > 0) continue;
    119     }
    120 
    121     if (a[0] == '-' && a[1] != '\0') {
    122       driver_errf(AS_TOOL, "unknown flag: %.*s",
    123                   KIT_SLICE_ARG(kit_slice_cstr(a)));
    124       return 1;
    125     }
    126 
    127     if (o->source) {
    128       driver_errf(AS_TOOL, "multiple inputs not supported");
    129       return 1;
    130     }
    131     o->source = a;
    132   }
    133 
    134   if (!o->source) {
    135     driver_errf(AS_TOOL, "no input file");
    136     as_usage();
    137     return 1;
    138   }
    139   if (!o->output_path) {
    140     driver_errf(AS_TOOL, "-o is required");
    141     return 1;
    142   }
    143   return 0;
    144 }
    145 
    146 int driver_as(int argc, char** argv) {
    147   DriverEnv env;
    148   AsOptions o = {0};
    149   DriverCflags cf = {0};
    150   DriverTargetFeatures tf = {0};
    151   KitContext ctx;
    152   KitPreprocessOptions pp;
    153   KitTarget* target = NULL;
    154   KitCompiler* compiler = NULL;
    155   KitWriter* writer = NULL;
    156   KitWriter* pp_writer = NULL;
    157   KitFileData src = {0};
    158   KitSlice input;
    159   KitSlice asm_input;
    160   KitAsmCompileOptions copts;
    161   KitAsmCompileOptions zero = {0};
    162   const uint8_t* pp_data;
    163   size_t pp_len;
    164   int rc = 1;
    165   int loaded = 0;
    166 
    167   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
    168     driver_help_as();
    169     return 0;
    170   }
    171 
    172   driver_env_init(&env);
    173 
    174   if (driver_cflags_init(&cf, &env, argc) != 0 ||
    175       driver_target_features_init(&tf, &env, argc) != 0) {
    176     driver_errf(AS_TOOL, "out of memory");
    177     driver_target_features_fini(&tf, &env);
    178     driver_cflags_fini(&cf, &env);
    179     driver_env_fini(&env);
    180     return 2;
    181   }
    182 
    183   if (as_parse(argc, argv, &o, &env, &cf, &tf) != 0) {
    184     driver_target_features_fini(&tf, &env);
    185     driver_cflags_fini(&cf, &env);
    186     driver_env_fini(&env);
    187     return 2;
    188   }
    189   driver_cflags_fill_pp(&cf, &pp);
    190 
    191   ctx = driver_env_to_context(&env);
    192 
    193   if (ctx.file_io->read_all(ctx.file_io->user, o.source, &src) != KIT_OK) {
    194     driver_errf(AS_TOOL, "failed to read: %.*s",
    195                 KIT_SLICE_ARG(kit_slice_cstr(o.source)));
    196     goto out;
    197   }
    198   loaded = 1;
    199 
    200   if (ctx.file_io->open_writer(ctx.file_io->user, o.output_path, &writer) !=
    201       KIT_OK) {
    202     driver_errf(AS_TOOL, "failed to open output: %.*s",
    203                 KIT_SLICE_ARG(kit_slice_cstr(o.output_path)));
    204     goto out;
    205   }
    206 
    207   if (driver_target_new(&ctx, o.target, &tf, AS_TOOL, &target) != KIT_OK ||
    208       driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
    209     driver_errf(AS_TOOL, "failed to initialize compiler");
    210     goto out;
    211   }
    212 
    213   copts = zero;
    214   copts.code.debug_info = o.debug_info;
    215 
    216   input.data = src.data;
    217   input.len = src.size;
    218   asm_input = input;
    219 
    220   if (driver_has_suffix(o.source, ".S")) {
    221     if (kit_writer_mem(ctx.heap, &pp_writer) != KIT_OK) {
    222       driver_errf(AS_TOOL, "out of memory");
    223       goto out;
    224     }
    225     if (kit_cpp_preprocess(compiler, &pp, kit_slice_cstr(o.source), &input,
    226                            pp_writer) != KIT_OK)
    227       goto out;
    228     if (kit_writer_status(pp_writer) != KIT_OK) {
    229       driver_errf(AS_TOOL, "failed to preprocess: %.*s",
    230                   KIT_SLICE_ARG(kit_slice_cstr(o.source)));
    231       goto out;
    232     }
    233     pp_data = kit_writer_mem_bytes(pp_writer, &pp_len);
    234     asm_input.data = pp_data;
    235     asm_input.len = pp_len;
    236   }
    237 
    238   {
    239     KitCompileSessionOptions sopts;
    240     KitCompileSession* session = NULL;
    241     KitSourceInput sin;
    242     KitObjBuilder* ob = NULL;
    243     KitStatus st;
    244     memset(&sopts, 0, sizeof(sopts));
    245     sopts.lang = KIT_LANG_ASM;
    246     sopts.compile.code = copts.code;
    247     sopts.compile.diagnostics = copts.diagnostics;
    248     sopts.compile.language_options = &copts;
    249     memset(&sin, 0, sizeof(sin));
    250     sin.name = kit_slice_cstr(o.source);
    251     sin.bytes = asm_input;
    252     sin.lang = KIT_LANG_ASM;
    253     st = kit_compile_session_new(compiler, &sopts, &session);
    254     if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob);
    255     if (st == KIT_OK) st = kit_obj_builder_emit(ob, writer);
    256     kit_obj_builder_free(ob);
    257     kit_compile_session_free(session);
    258     rc = st == KIT_OK ? 0 : 1;
    259   }
    260 
    261 out:
    262   if (compiler) driver_compiler_free(compiler);
    263   kit_target_free(target);
    264   if (pp_writer) kit_writer_close(pp_writer);
    265   if (writer) kit_writer_close(writer);
    266   if (loaded) ctx.file_io->release(ctx.file_io->user, &src);
    267   driver_target_features_fini(&tf, &env);
    268   driver_cflags_fini(&cf, &env);
    269   driver_env_fini(&env);
    270   return rc;
    271 }