Skip to content

Commit

Permalink
Support whole-program LTO
Browse files Browse the repository at this point in the history
Build and install an LTO version of libc.a and the startup files,
alongside the non-LTO versions.

This also adds support for the proposed `__main_argc_argv` convention,
supporting compilers both with and without that change.
  • Loading branch information
sunfishcode committed Dec 20, 2019
1 parent a280fea commit 041d027
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 307 deletions.
546 changes: 294 additions & 252 deletions Makefile

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions basics/crt/crt1.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ void _start(void) {
// The linker synthesizes this to call constructors.
__wasm_call_ctors();

// 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`.
// Call `__original_main` which will either be the application's zero-argument
// `__original_main` function or a libc routine which calls `__main_void`.
// TODO: Call `main` directly once we no longer have to support old compilers.
int r = __original_main();

// Call atexit functions, destructors, stdio cleanup, etc.
Expand Down
2 changes: 2 additions & 0 deletions expected/wasm32-wasi/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ __log2_data
__log2f_data
__log_data
__logf_data
__main_argc_argv
__main_void
__math_divzero
__math_divzerof
__math_invalid
Expand Down
8 changes: 3 additions & 5 deletions libc-bottom-half/crt/crt1.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <wasi/api.h>
#include <wasi/libc.h>
extern void __wasm_call_ctors(void);
extern int __original_main(void);
extern void __prepare_for_exit(void);
Expand All @@ -8,10 +7,9 @@ void _start(void) {
// The linker synthesizes this to call constructors.
__wasm_call_ctors();

// 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`.
// Call `__original_main` which will either be the application's zero-argument
// `__original_main` function or a libc routine which calls `__main_void`.
// TODO: Call `main` directly once we no longer have to support old compilers.
int r = __original_main();

// Call atexit functions, destructors, stdio cleanup, etc.
Expand Down
15 changes: 15 additions & 0 deletions libc-bottom-half/sources/__main_argc_argv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <wasi/api.h>
#include <wasi/libc.h>
#include <stdlib.h>
#include <sysexits.h>

// New compilers define `__main_argc_argv`. If that doesn't exist, we
// may get called here. Old compilers define `main` expecting an
// argv/argc, so call that.
// TODO: Remove this layer when we no longer have to support old compilers.
int __wasilibc_main(int argc, char *argv[]) asm("main");

__attribute__((weak, nodebug))
int __main_argc_argv(int argc, char *argv[]) {
return __wasilibc_main(argc, argv);
}
55 changes: 55 additions & 0 deletions libc-bottom-half/sources/__main_void.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include <wasi/api.h>
#include <wasi/libc.h>
#include <stdlib.h>
#include <sysexits.h>

// The user's `main` function, expecting arguments.
int __main_argc_argv(int argc, char *argv[]);

// If the user's `main` function expects arguments, the compiler will rename
// it to `__main_argc_argv`, and this version will get linked in, which
// initializes the argument data and calls `__main_argc_argv`.
__attribute__((weak, nodebug))
int __main_void(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_ERRNO_SUCCESS) {
_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.
// TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is updated with char8 support.
err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf);
if (err != __WASI_ERRNO_SUCCESS) {
free(argv_buf);
free(argv);
_Exit(EX_OSERR);
}

// Call `__main_argc_argv` with the arguments!
return __main_argc_argv(argc, argv);
}
52 changes: 6 additions & 46 deletions libc-bottom-half/sources/__original_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,13 @@
#include <stdlib.h>
#include <sysexits.h>

// The user's `main` function, expecting arguments.
int main(int argc, char *argv[]);
// Old compilers define `__original_main`. If that doesn't exist, we
// get called here. New compilers define `__main_void`. If that doesn't
// exist, we'll try something else.
// TODO: Remove this layer when we no longer have to support old compilers.
int __main_void(void);

// 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`.
__attribute__((weak))
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_ERRNO_SUCCESS) {
_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.
// TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is updated with char8 support.
err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf);
if (err != __WASI_ERRNO_SUCCESS) {
free(argv_buf);
free(argv);
_Exit(EX_OSERR);
}

// Call main with the arguments!
return main(argc, argv);
return __main_void();
}

0 comments on commit 041d027

Please sign in to comment.