Skip to content

Commit 8638ab9

Browse files
committed
Add support for __main_argc_argv.
This adds support for the `__main_argc_argv` change, while preserving compatibility with `__original_main`. This is needed by the LTO build because the `__original_main` hack works in LLVM codegen, which is after LTO. The `__main_argc_argv` change is implemented in clang, which makes it properly visible to LTO.
1 parent 575e157 commit 8638ab9

File tree

6 files changed

+78
-60
lines changed

6 files changed

+78
-60
lines changed

basics/crt/crt1.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ void _start(void) {
77
// The linker synthesizes this to call constructors.
88
__wasm_call_ctors();
99

10-
// Call `__original_main` which will either be the application's
11-
// zero-argument `main` function (renamed by the compiler) or a libc
12-
// routine which populates `argv` and `argc` and calls the application's
13-
// two-argument `main`.
10+
// Call `__original_main` which will either be the application's zero-argument
11+
// `__original_main` function or a libc routine which calls `__main_void`.
12+
// TODO: Call `main` directly once we no longer have to support old compilers.
1413
int r = __original_main();
1514

1615
// Call atexit functions, destructors, stdio cleanup, etc.

expected/wasm32-wasi/defined-symbols.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ __log2f_data
140140
__log_data
141141
__logf_data
142142
__lseek
143+
__main_argc_argv
144+
__main_void
143145
__math_divzero
144146
__math_divzerof
145147
__math_invalid

libc-bottom-half/crt/crt1.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include <wasi/api.h>
2-
#include <wasi/libc.h>
32
extern void __wasm_call_ctors(void);
43
extern int __original_main(void);
54
extern void __prepare_for_exit(void);
@@ -8,10 +7,9 @@ void _start(void) {
87
// The linker synthesizes this to call constructors.
98
__wasm_call_ctors();
109

11-
// Call `__original_main` which will either be the application's
12-
// zero-argument `main` function (renamed by the compiler) or a libc
13-
// routine which populates `argv` and `argc` and calls the application's
14-
// two-argument `main`.
10+
// Call `__original_main` which will either be the application's zero-argument
11+
// `__original_main` function or a libc routine which calls `__main_void`.
12+
// TODO: Call `main` directly once we no longer have to support old compilers.
1513
int r = __original_main();
1614

1715
// Call atexit functions, destructors, stdio cleanup, etc.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// New compilers define `__main_argc_argv`. If that doesn't exist, we
2+
// may get called here. Old compilers define `main` expecting an
3+
// argv/argc, so call that.
4+
// TODO: Remove this layer when we no longer have to support old compilers.
5+
int __wasilibc_main(int argc, char *argv[]) asm("main");
6+
7+
__attribute__((weak, nodebug))
8+
int __main_argc_argv(int argc, char *argv[]) {
9+
return __wasilibc_main(argc, argv);
10+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <wasi/api.h>
2+
#include <stdlib.h>
3+
#include <sysexits.h>
4+
5+
// The user's `main` function, expecting arguments.
6+
int __main_argc_argv(int argc, char *argv[]);
7+
8+
// If the user's `main` function expects arguments, the compiler will rename
9+
// it to `__main_argc_argv`, and this version will get linked in, which
10+
// initializes the argument data and calls `__main_argc_argv`.
11+
__attribute__((weak, nodebug))
12+
int __main_void(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_ERRNO_SUCCESS) {
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+
// TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is updated with char8 support.
45+
err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf);
46+
if (err != __WASI_ERRNO_SUCCESS) {
47+
free(argv_buf);
48+
free(argv);
49+
_Exit(EX_OSERR);
50+
}
51+
52+
// Call `__main_argc_argv` with the arguments!
53+
return __main_argc_argv(argc, argv);
54+
}
Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,10 @@
1-
#include <wasi/api.h>
2-
#include <wasi/libc.h>
3-
#include <stdlib.h>
4-
#include <sysexits.h>
1+
// Old compilers define `__original_main`. If that doesn't exist, we
2+
// get called here. New compilers define `__main_void`. If that doesn't
3+
// exist, we'll try something else.
4+
// TODO: Remove this layer when we no longer have to support old compilers.
5+
int __main_void(void);
56

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`.
127
__attribute__((weak))
138
int __original_main(void) {
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 argc;
19-
err = __wasi_args_sizes_get(&argc, &argv_buf_size);
20-
if (err != __WASI_ERRNO_SUCCESS) {
21-
_Exit(EX_OSERR);
22-
}
23-
24-
// Add 1 for the NULL pointer to mark the end, and check for overflow.
25-
size_t num_ptrs = argc + 1;
26-
if (num_ptrs == 0) {
27-
_Exit(EX_SOFTWARE);
28-
}
29-
30-
// Allocate memory for storing the argument chars.
31-
char *argv_buf = malloc(argv_buf_size);
32-
if (argv_buf == NULL) {
33-
_Exit(EX_SOFTWARE);
34-
}
35-
36-
// Allocate memory for the array of pointers. This uses `calloc` both to
37-
// handle overflow and to initialize the NULL pointer at the end.
38-
char **argv = calloc(num_ptrs, sizeof(char *));
39-
if (argv == NULL) {
40-
free(argv_buf);
41-
_Exit(EX_SOFTWARE);
42-
}
43-
44-
// Fill the argument chars, and the argv array with pointers into those chars.
45-
// TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is updated with char8 support.
46-
err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf);
47-
if (err != __WASI_ERRNO_SUCCESS) {
48-
free(argv_buf);
49-
free(argv);
50-
_Exit(EX_OSERR);
51-
}
52-
53-
// Call main with the arguments!
54-
return main(argc, argv);
9+
return __main_void();
5510
}

0 commit comments

Comments
 (0)