]> git.proxmox.com Git - wasi-libc.git/commitdiff
Call `populate_args` only if we actually need command-line arguments (#112)
authorDan Gohman <sunfish@mozilla.com>
Fri, 25 Oct 2019 00:30:46 +0000 (17:30 -0700)
committerGitHub <noreply@github.com>
Fri, 25 Oct 2019 00:30:46 +0000 (17:30 -0700)
* 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`.

expected/wasm32-wasi/defined-symbols.txt
libc-bottom-half/cloudlibc/src/include/stdlib.h
libc-bottom-half/crt/crt1.c
libc-bottom-half/sources/__original_main.c [new file with mode: 0644]

index 39761b51e08cf9634180f519ef00114ae7ac7694..6b97f522d02acd2b6a4b0a3120d3619ba58772f6 100644 (file)
@@ -160,6 +160,7 @@ __ofl_lock
 __ofl_unlock
 __optpos
 __optreset
+__original_main
 __overflow
 __p1evll
 __pio2_hi
index 949caf31d76abefeadc3b4919789f7ecf3c88d39..134a0ba34a36ac3d5c68d8745f08a2a41c2dc27d 100644 (file)
@@ -110,9 +110,11 @@ typedef __wchar_t wchar_t;
 #define MB_CUR_MAX_L MB_CUR_MAX_L
 
 #define alloca(size) __builtin_alloca(size)
+#endif
 
 __BEGIN_DECLS
 _Noreturn void _Exit(int);
+#ifdef __wasilibc_unmodified_upstream
 size_t MB_CUR_MAX_L(__locale_t);
 long a64l(const char *);
 #endif
@@ -196,8 +198,8 @@ size_t wcstombs_l(char *__restrict, const wchar_t *__restrict, size_t,
                   __locale_t);
 int wctomb(char *, wchar_t);
 int wctomb_l(char *, wchar_t, __locale_t);
-__END_DECLS
 #endif
+__END_DECLS
 
 #if _CLOUDLIBC_INLINE_FUNCTIONS
 #ifdef __wasilibc_unmodified_upstream
index 76ecb554d94c978a994ca51785ee06f5db5b971c..247604ad687e67e328139dbd3e0454d49e6cf204 100644 (file)
@@ -6,56 +6,10 @@
 
 __wasi_errno_t __wasilibc_populate_environ(void) __attribute__((weak));
 extern void __wasm_call_ctors(void);
-extern int main(int, char *[]);
+extern int __original_main(void);
 extern void __prepare_for_exit(void);
 void _Exit(int) __attribute__((noreturn));
 
-static __wasi_errno_t populate_args(size_t *argc, char ***argv) {
-    __wasi_errno_t err;
-
-    // Get the sizes of the arrays we'll have to create to copy in the args.
-    size_t argv_buf_size;
-    size_t new_argc;
-    err = __wasi_args_sizes_get(&new_argc, &argv_buf_size);
-    if (err != __WASI_ESUCCESS) {
-        return err;
-    }
-    if (new_argc == 0) {
-        return __WASI_ESUCCESS;
-    }
-
-    // Add 1 for the NULL pointer to mark the end, and check for overflow.
-    size_t num_ptrs = new_argc + 1;
-    if (num_ptrs == 0) {
-        return __WASI_ENOMEM;
-    }
-
-    // Allocate memory for storing the argument chars.
-    char *argv_buf = malloc(argv_buf_size);
-    if (argv_buf == NULL) {
-        return __WASI_ENOMEM;
-    }
-
-    // Allocate memory for the array of pointers. This uses `calloc` both to
-    // handle overflow and to initialize the NULL pointer at the end.
-    char **argv_ptrs = calloc(num_ptrs, sizeof(char *));
-    if (argv_ptrs == NULL) {
-        free(argv_buf);
-        return __WASI_ENOMEM;
-    }
-
-    // Fill the argument chars, and the argv array with pointers into those chars.
-    err = __wasi_args_get(argv_ptrs, argv_buf);
-    if (err == __WASI_ESUCCESS) {
-        *argc = new_argc;
-        *argv = argv_ptrs;
-    } else {
-        free(argv_buf);
-        free(argv_ptrs);
-    }
-    return err;
-}
-
 static __wasi_errno_t populate_libpreopen(void) {
     __wasilibc_init_preopen();
 
@@ -110,18 +64,14 @@ void _start(void) {
         }
     }
 
-    // Fill in the arguments from WASI syscalls.
-    size_t argc;
-    char **argv;
-    if (populate_args(&argc, &argv) != __WASI_ESUCCESS) {
-        _Exit(EX_OSERR);
-    }
-
     // The linker synthesizes this to call constructors.
     __wasm_call_ctors();
 
-    // Call main with the arguments.
-    int r = main(argc, argv);
+    // Call `__original_main` which will either be the application's
+    // zero-argument `main` function (renamed by the compiler) or a libc
+    // routine which populates `argv` and `argc` and calls the application's
+    // two-argument `main`.
+    int r = __original_main();
 
     // Call atexit functions, destructors, stdio cleanup, etc.
     __prepare_for_exit();
diff --git a/libc-bottom-half/sources/__original_main.c b/libc-bottom-half/sources/__original_main.c
new file mode 100644 (file)
index 0000000..b138853
--- /dev/null
@@ -0,0 +1,53 @@
+#include <wasi/core.h>
+#include <wasi/libc.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+// The user's `main` function, expecting arguments.
+int main(int argc, char *argv[]);
+
+// If the user's `main` function expects arguments, the compiler won't emit
+// an `__original_main` function so this version will get linked in, which
+// initializes the argument data and calls `main`.
+int __original_main(void) {
+    __wasi_errno_t err;
+
+    // Get the sizes of the arrays we'll have to create to copy in the args.
+    size_t argv_buf_size;
+    size_t argc;
+    err = __wasi_args_sizes_get(&argc, &argv_buf_size);
+    if (err != __WASI_ESUCCESS) {
+        _Exit(EX_OSERR);
+    }
+
+    // Add 1 for the NULL pointer to mark the end, and check for overflow.
+    size_t num_ptrs = argc + 1;
+    if (num_ptrs == 0) {
+        _Exit(EX_SOFTWARE);
+    }
+
+    // Allocate memory for storing the argument chars.
+    char *argv_buf = malloc(argv_buf_size);
+    if (argv_buf == NULL) {
+        _Exit(EX_SOFTWARE);
+    }
+
+    // Allocate memory for the array of pointers. This uses `calloc` both to
+    // handle overflow and to initialize the NULL pointer at the end.
+    char **argv = calloc(num_ptrs, sizeof(char *));
+    if (argv == NULL) {
+        free(argv_buf);
+        _Exit(EX_SOFTWARE);
+    }
+
+    // Fill the argument chars, and the argv array with pointers into those chars.
+    err = __wasi_args_get(argv, argv_buf);
+    if (err != __WASI_ESUCCESS) {
+        free(argv_buf);
+        free(argv);
+        _Exit(EX_OSERR);
+    }
+
+    // Call main with the arguments!
+    return main(argc, argv);
+}