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}