Skip to content

Commit afbf94c

Browse files
authored
Call populate_args only if we actually need command-line arguments (#112)
* Link `populate_args` only if we actually need command-line arguments. This avoids linking in the argv/argc initialization code, and the __wasi_args_sizes_get and __wasi_args_get imports, in programs that don't use command-line arguments. The way this works is, if the user writes `int main(int argc, char *argv[])`, the argument initialization code is loaded, and if they write `int main(void)`, it's not loaded. This promotes the `__original_main` mechanism into an effective contract between the compiler and libc, which wasn't its original purpose, however it seems to fit this purpose quite well. * Document that `__original_main` may be the user's zero-arg `main`.
1 parent 1f11b91 commit afbf94c

File tree

4 files changed

+63
-57
lines changed

4 files changed

+63
-57
lines changed

expected/wasm32-wasi/defined-symbols.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ __ofl_lock
160160
__ofl_unlock
161161
__optpos
162162
__optreset
163+
__original_main
163164
__overflow
164165
__p1evll
165166
__pio2_hi

libc-bottom-half/cloudlibc/src/include/stdlib.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ typedef __wchar_t wchar_t;
110110
#define MB_CUR_MAX_L MB_CUR_MAX_L
111111

112112
#define alloca(size) __builtin_alloca(size)
113+
#endif
113114

114115
__BEGIN_DECLS
115116
_Noreturn void _Exit(int);
117+
#ifdef __wasilibc_unmodified_upstream
116118
size_t MB_CUR_MAX_L(__locale_t);
117119
long a64l(const char *);
118120
#endif
@@ -196,8 +198,8 @@ size_t wcstombs_l(char *__restrict, const wchar_t *__restrict, size_t,
196198
__locale_t);
197199
int wctomb(char *, wchar_t);
198200
int wctomb_l(char *, wchar_t, __locale_t);
199-
__END_DECLS
200201
#endif
202+
__END_DECLS
201203

202204
#if _CLOUDLIBC_INLINE_FUNCTIONS
203205
#ifdef __wasilibc_unmodified_upstream

libc-bottom-half/crt/crt1.c

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,10 @@
66

77
__wasi_errno_t __wasilibc_populate_environ(void) __attribute__((weak));
88
extern void __wasm_call_ctors(void);
9-
extern int main(int, char *[]);
9+
extern int __original_main(void);
1010
extern void __prepare_for_exit(void);
1111
void _Exit(int) __attribute__((noreturn));
1212

13-
static __wasi_errno_t populate_args(size_t *argc, char ***argv) {
14-
__wasi_errno_t err;
15-
16-
// Get the sizes of the arrays we'll have to create to copy in the args.
17-
size_t argv_buf_size;
18-
size_t new_argc;
19-
err = __wasi_args_sizes_get(&new_argc, &argv_buf_size);
20-
if (err != __WASI_ESUCCESS) {
21-
return err;
22-
}
23-
if (new_argc == 0) {
24-
return __WASI_ESUCCESS;
25-
}
26-
27-
// Add 1 for the NULL pointer to mark the end, and check for overflow.
28-
size_t num_ptrs = new_argc + 1;
29-
if (num_ptrs == 0) {
30-
return __WASI_ENOMEM;
31-
}
32-
33-
// Allocate memory for storing the argument chars.
34-
char *argv_buf = malloc(argv_buf_size);
35-
if (argv_buf == NULL) {
36-
return __WASI_ENOMEM;
37-
}
38-
39-
// Allocate memory for the array of pointers. This uses `calloc` both to
40-
// handle overflow and to initialize the NULL pointer at the end.
41-
char **argv_ptrs = calloc(num_ptrs, sizeof(char *));
42-
if (argv_ptrs == NULL) {
43-
free(argv_buf);
44-
return __WASI_ENOMEM;
45-
}
46-
47-
// Fill the argument chars, and the argv array with pointers into those chars.
48-
err = __wasi_args_get(argv_ptrs, argv_buf);
49-
if (err == __WASI_ESUCCESS) {
50-
*argc = new_argc;
51-
*argv = argv_ptrs;
52-
} else {
53-
free(argv_buf);
54-
free(argv_ptrs);
55-
}
56-
return err;
57-
}
58-
5913
static __wasi_errno_t populate_libpreopen(void) {
6014
__wasilibc_init_preopen();
6115

@@ -110,18 +64,14 @@ void _start(void) {
11064
}
11165
}
11266

113-
// Fill in the arguments from WASI syscalls.
114-
size_t argc;
115-
char **argv;
116-
if (populate_args(&argc, &argv) != __WASI_ESUCCESS) {
117-
_Exit(EX_OSERR);
118-
}
119-
12067
// The linker synthesizes this to call constructors.
12168
__wasm_call_ctors();
12269

123-
// Call main with the arguments.
124-
int r = main(argc, argv);
70+
// Call `__original_main` which will either be the application's
71+
// zero-argument `main` function (renamed by the compiler) or a libc
72+
// routine which populates `argv` and `argc` and calls the application's
73+
// two-argument `main`.
74+
int r = __original_main();
12575

12676
// Call atexit functions, destructors, stdio cleanup, etc.
12777
__prepare_for_exit();
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <wasi/core.h>
2+
#include <wasi/libc.h>
3+
#include <stdlib.h>
4+
#include <sysexits.h>
5+
6+
// The user's `main` function, expecting arguments.
7+
int main(int argc, char *argv[]);
8+
9+
// If the user's `main` function expects arguments, the compiler won't emit
10+
// an `__original_main` function so this version will get linked in, which
11+
// initializes the argument data and calls `main`.
12+
int __original_main(void) {
13+
__wasi_errno_t err;
14+
15+
// Get the sizes of the arrays we'll have to create to copy in the args.
16+
size_t argv_buf_size;
17+
size_t argc;
18+
err = __wasi_args_sizes_get(&argc, &argv_buf_size);
19+
if (err != __WASI_ESUCCESS) {
20+
_Exit(EX_OSERR);
21+
}
22+
23+
// Add 1 for the NULL pointer to mark the end, and check for overflow.
24+
size_t num_ptrs = argc + 1;
25+
if (num_ptrs == 0) {
26+
_Exit(EX_SOFTWARE);
27+
}
28+
29+
// Allocate memory for storing the argument chars.
30+
char *argv_buf = malloc(argv_buf_size);
31+
if (argv_buf == NULL) {
32+
_Exit(EX_SOFTWARE);
33+
}
34+
35+
// Allocate memory for the array of pointers. This uses `calloc` both to
36+
// handle overflow and to initialize the NULL pointer at the end.
37+
char **argv = calloc(num_ptrs, sizeof(char *));
38+
if (argv == NULL) {
39+
free(argv_buf);
40+
_Exit(EX_SOFTWARE);
41+
}
42+
43+
// Fill the argument chars, and the argv array with pointers into those chars.
44+
err = __wasi_args_get(argv, argv_buf);
45+
if (err != __WASI_ESUCCESS) {
46+
free(argv_buf);
47+
free(argv);
48+
_Exit(EX_OSERR);
49+
}
50+
51+
// Call main with the arguments!
52+
return main(argc, argv);
53+
}

0 commit comments

Comments
 (0)