master
  1#ifdef __wasilibc_use_wasip2
  2#include <wasi/wasip2.h>
  3#else
  4#include <wasi/api.h>
  5#endif
  6#include <stdlib.h>
  7#include <sysexits.h>
  8
  9// The user's `main` function, expecting arguments.
 10//
 11// Note that we make this a weak symbol so that it will have a
 12// `WASM_SYM_BINDING_WEAK` flag in libc.so, which tells the dynamic linker that
 13// it need not be defined (e.g. in reactor-style apps with no main function).
 14// See also the TODO comment on `__main_void` below.
 15__attribute__((__weak__))
 16int __main_argc_argv(int argc, char *argv[]);
 17
 18// If the user's `main` function expects arguments, the compiler will rename
 19// it to `__main_argc_argv`, and this version will get linked in, which
 20// initializes the argument data and calls `__main_argc_argv`.
 21//
 22// TODO: Ideally this function would be defined in a crt*.o file and linked in
 23// as necessary by the Clang driver.  However, moving it to crt1-command.c
 24// breaks `--no-gc-sections`, so we'll probably need to create a new file
 25// (e.g. crt0.o or crtend.o) and teach Clang to use it when needed.
 26__attribute__((__weak__, nodebug))
 27int __main_void(void) {
 28#ifdef __wasilibc_use_wasip2
 29    wasip2_list_string_t argument_list;
 30
 31    environment_get_arguments(&argument_list);
 32
 33    // Add 1 for the NULL pointer to mark the end, and check for overflow.
 34    size_t argc = argument_list.len;
 35    size_t num_ptrs = argc + 1;
 36    if (num_ptrs == 0) {
 37        wasip2_list_string_free(&argument_list);
 38        _Exit(EX_SOFTWARE);
 39    }
 40
 41    // Allocate memory for the array of pointers. This uses `calloc` both to
 42    // handle overflow and to initialize the NULL pointer at the end.
 43    char **argv = calloc(num_ptrs, sizeof(char *));
 44    if (argv == NULL) {
 45        wasip2_list_string_free(&argument_list);
 46        _Exit(EX_SOFTWARE);
 47    }
 48
 49    // Copy the arguments
 50    for (size_t i = 0; i < argc; i++) {
 51        wasip2_string_t wasi_string = argument_list.ptr[i];
 52        size_t len = wasi_string.len;
 53        argv[i] = malloc(len + 1);
 54        if (!argv[i]) {
 55            wasip2_list_string_free(&argument_list);
 56            _Exit(EX_SOFTWARE);
 57        }
 58        memcpy(argv[i], wasi_string.ptr, len);
 59        argv[i][len] = '\0';
 60    }
 61
 62    // Free the WASI argument list
 63    wasip2_list_string_free(&argument_list);
 64
 65    // Call `__main_argc_argv` with the arguments!
 66    return __main_argc_argv(argc, argv);
 67#else
 68    __wasi_errno_t err;
 69
 70    // Get the sizes of the arrays we'll have to create to copy in the args.
 71    size_t argv_buf_size;
 72    size_t argc;
 73    err = __wasi_args_sizes_get(&argc, &argv_buf_size);
 74    if (err != __WASI_ERRNO_SUCCESS) {
 75        _Exit(EX_OSERR);
 76    }
 77
 78    // Add 1 for the NULL pointer to mark the end, and check for overflow.
 79    size_t num_ptrs = argc + 1;
 80    if (num_ptrs == 0) {
 81        _Exit(EX_SOFTWARE);
 82    }
 83
 84    // Allocate memory for storing the argument chars.
 85    char *argv_buf = malloc(argv_buf_size);
 86    if (argv_buf == NULL) {
 87        _Exit(EX_SOFTWARE);
 88    }
 89
 90    // Allocate memory for the array of pointers. This uses `calloc` both to
 91    // handle overflow and to initialize the NULL pointer at the end.
 92    char **argv = calloc(num_ptrs, sizeof(char *));
 93    if (argv == NULL) {
 94        free(argv_buf);
 95        _Exit(EX_SOFTWARE);
 96    }
 97
 98    // Fill the argument chars, and the argv array with pointers into those chars.
 99    // TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is updated with char8 support.
100    err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf);
101    if (err != __WASI_ERRNO_SUCCESS) {
102        free(argv_buf);
103        free(argv);
104        _Exit(EX_OSERR);
105    }
106
107    // Call `__main_argc_argv` with the arguments!
108    return __main_argc_argv(argc, argv);
109#endif
110}