freestanding: small fixes (#9760)

pull/9777/head
crthpl 2021-04-16 16:38:41 -07:00 committed by GitHub
parent cb70ffef59
commit 0a1d0e062d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 138 deletions

View File

@ -31,42 +31,51 @@ see also `v help build`.
-bare-builtin-dir <bare-builtin-dir> -bare-builtin-dir <bare-builtin-dir>
Use with `-freestanding`. This specifies the directory to the Use with `-freestanding`. This specifies the directory to the
implementation of some basic builtin functions. The list is as follows: implementation of some basic builtin functions. The list is as follows:
memcpy(dest &byte, src &byte, n int) &byte
Moves n bytes from dest to src, and returns dest
[export: 'malloc']
__malloc(n int) &byte
Allocates n bytes of memory and returns the pointer to the first byte
strlen(s &byte) int
Returns the amount of bytes until the first `0`, starting at s
realloc(old_area &byte, new_size int) &byte
Allocates a new area of size new_size, copies old_area
to the new area, and returns a pointer to the new area.
memset(s &byte, c int, n int) &byte
Sets n bytes starting at s to c (c is casted to a char)
and returns s.
memmove(dest &byte, src &byte, n int) &byte
Like memcpy, but guaranteed to work if dest and src overlap.
[export: 'calloc']
__calloc(nmemb int, size int) &byte
Like malloc, but sets all the bytes to `0` first.
getchar() int
Read one character from stdin and return it.
memcmp(a &byte, b &byte, n int) int
Compare two buffers of length n. If a and b are equal, return 0.
Otherwise, return the difference between the first different letter.
[export: 'free']
__free(ptr &byte)
Free the block of memory ptr allocated by malloc.
vsprintf(str &char, format &char, ap va_list) int
See `man vsprintf`.
vsnprintf(str &char, size int, format &char, ap va_list) int
See `man vsnprintf`.
bare_print(buf &byte, len u64) bare_print(buf &byte, len u64)
Print len charecters from the buffer pointed to by buf to stdout. Print len charecters from the buffer pointed to by buf to stdout.
bare_eprint(buf &byte, len u64) bare_eprint(buf &byte, len u64)
Print len charecters from the buffer pointed to by buf to stderr. Print len charecters from the buffer pointed to by buf to stderr.
bare_panic(msg string)
Print "V panic: " + msg, along with an optional backtrace and/or the V commit hash, and then exit.
[export: 'malloc']
__malloc(n size_t) &C.void
Allocates n bytes of memory and returns the pointer to the first byte
[export: 'free']
__free(ptr &C.void)
Free the block of memory ptr allocated by malloc.
realloc(old_area &C.void, new_size size_t) &C.void
Allocates a new area of size new_size, copies old_area
to the new area, and returns a pointer to the new area.
[export: 'calloc']
__calloc(nmemb size_t, size size_t) &C.void
Like malloc, but sets all the bytes to `0` first.
memcpy(dest &C.void, src &C.void, n size_t) &C.void
Moves n bytes from dest to src, and returns dest
memmove(dest &C.void, src &C.void, n size_t) &C.void
Like memcpy, but guaranteed to work if dest and src overlap.
memcmp(a &C.void, b &C.void, n size_t) int
Compare two buffers of length n. If a and b are equal, return 0.
Otherwise, return the difference between the first different letter.
strlen(s &C.void) size_t
Returns the amount of bytes until the first `0`, starting at s
memset(s &C.void, c int, n size_t) &C.void
Sets n bytes starting at s to c (c is casted to a char)
and returns s.
getchar() int
Read one character from stdin and return it.
Print "V Panic" + msg, along with an optional backtrace, and then exit.
vsprintf(str &char, format &char, ap va_list) int
See `man vsprintf`.
vsnprintf(str &char, size size_t, format &char, ap va_list) int
See `man vsnprintf`.
bare_backtrace() string
Return a backtrace that can be printed. If backtraces are not
supported, return a message stating that backtraces do not work.
[export: 'exit']
__exit(code int)
Exit with code code. code is allowed to be ignored.
The module decleration should be `builtin`. The default linux The module decleration should be `builtin`. The default Linux
implementation can be found in `vlib/builtin/linux_bare`. implementation can be found in `vlib/builtin/linux_bare`.
-os <os>, -target-os <os> -os <os>, -target-os <os>

View File

@ -22,7 +22,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
// module is less likely to change than function, etc... // module is less likely to change than function, etc...
// During edits, the line number will change most frequently, // During edits, the line number will change most frequently,
// so it is last // so it is last
$if !freestanding { $if freestanding {
bare_panic(s)
} $else {
eprintln('================ V panic ================') eprintln('================ V panic ================')
eprintln(' module: $mod') eprintln(' module: $mod')
eprintln(' function: ${fn_name}()') eprintln(' function: ${fn_name}()')
@ -30,31 +32,26 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
eprintln(' file: $file:$line_no') eprintln(' file: $file:$line_no')
eprintln(' v hash: $vcommithash()') eprintln(' v hash: $vcommithash()')
eprintln('=========================================') eprintln('=========================================')
} $else { $if exit_after_panic_message ? {
eprint('V panic: ')
eprintln(s)
}
$if exit_after_panic_message ? {
C.exit(1)
} $else {
$if no_backtrace ? {
C.exit(1) C.exit(1)
} $else { } $else {
$if tinyc { $if no_backtrace ? {
C.exit(1)
} $else {
$if tinyc {
$if panics_break_into_debugger ? {
break_if_debugger_attached()
} $else {
C.tcc_backtrace(c'Backtrace')
}
C.exit(1)
}
print_backtrace_skipping_top_frames(1)
$if panics_break_into_debugger ? { $if panics_break_into_debugger ? {
break_if_debugger_attached() break_if_debugger_attached()
} $else {
C.tcc_backtrace(c'Backtrace')
} }
C.exit(1) C.exit(1)
} }
$if !freestanding {
print_backtrace_skipping_top_frames(1)
}
$if panics_break_into_debugger ? {
break_if_debugger_attached()
}
C.exit(1)
} }
} }
} }
@ -66,30 +63,32 @@ pub fn panic_optional_not_set(s string) {
// panic prints a nice error message, then exits the process with exit code of 1. // panic prints a nice error message, then exits the process with exit code of 1.
// It also shows a backtrace on most platforms. // It also shows a backtrace on most platforms.
pub fn panic(s string) { pub fn panic(s string) {
eprint('V panic: ') $if freestanding {
eprintln(s) bare_panic(s)
eprintln('v hash: $vcommithash()')
$if exit_after_panic_message ? {
C.exit(1)
} $else { } $else {
$if no_backtrace ? { eprint('V panic: ')
eprintln(s)
eprintln('v hash: $vcommithash()')
$if exit_after_panic_message ? {
C.exit(1) C.exit(1)
} $else { } $else {
$if tinyc { $if no_backtrace ? {
C.exit(1)
} $else {
$if tinyc {
$if panics_break_into_debugger ? {
break_if_debugger_attached()
} $else {
C.tcc_backtrace(c'Backtrace')
}
C.exit(1)
}
print_backtrace_skipping_top_frames(1)
$if panics_break_into_debugger ? { $if panics_break_into_debugger ? {
break_if_debugger_attached() break_if_debugger_attached()
} $else {
C.tcc_backtrace(c'Backtrace')
} }
C.exit(1) C.exit(1)
} }
$if !freestanding {
print_backtrace_skipping_top_frames(1)
}
$if panics_break_into_debugger ? {
break_if_debugger_attached()
}
C.exit(1)
} }
} }
} }

View File

@ -32,7 +32,9 @@ pub fn print_backtrace() {
// 1 frame for print_backtrace itself // 1 frame for print_backtrace itself
// ... print the rest of the backtrace frames ... // ... print the rest of the backtrace frames ...
// => top 2 frames should be skipped, since they will not be informative to the developer // => top 2 frames should be skipped, since they will not be informative to the developer
$if !freestanding { $if freestanding {
println(bare_backtrace())
} $else {
print_backtrace_skipping_top_frames(2) print_backtrace_skipping_top_frames(2)
} }
} }

View File

@ -1,72 +1,76 @@
module builtin module builtin
[unsafe] [unsafe]
pub fn memcpy(dest &byte, src &byte, n int) &byte { pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void {
dest_ := unsafe { &byte(dest) }
src_ := unsafe { &byte(src) }
unsafe { unsafe {
for i in 0 .. n { for i in 0 .. int(n) {
dest[i] = src[i] dest_[i] = src_[i]
} }
return dest
} }
return dest
} }
[export: 'malloc'] [export: 'malloc']
[unsafe] [unsafe]
fn __malloc(n int) &byte { fn __malloc(n size_t) &C.void {
return unsafe { malloc(n) } return unsafe { malloc(int(n)) }
} }
[unsafe] [unsafe]
fn strlen(s &byte) int { fn strlen(_s &C.void) size_t {
s := unsafe { &byte(_s) }
mut i := 0 mut i := 0
for ; unsafe { s[i] } != 0; i++ {} for ; unsafe { s[i] } != 0; i++ {}
return i return size_t(i)
} }
[unsafe] [unsafe]
fn realloc(old_area &byte, new_size int) &byte { fn realloc(old_area &C.void, new_size size_t) &C.void {
if old_area == 0 { if old_area == 0 {
return unsafe { malloc(new_size) } return unsafe { malloc(int(new_size)) }
} }
if new_size == 0 { if new_size == size_t(0) {
unsafe { free(old_area) } unsafe { free(old_area) }
return 0 return 0
} }
old_size := unsafe { *(&u64(old_area - sizeof(u64))) } old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
if new_size <= old_size { if u64(new_size) <= old_size {
return old_area return old_area
} else { } else {
new_area := unsafe { malloc(new_size) } new_area := unsafe { malloc(int(new_size)) }
unsafe { memmove(new_area, old_area, int(old_size)) } unsafe { memmove(new_area, old_area, size_t(old_size)) }
unsafe { free(old_area) } unsafe { free(old_area) }
return new_area return new_area
} }
} }
[unsafe] [unsafe]
fn memset(_s &byte, _c int, n int) &byte { fn memset(s &C.void, c int, n size_t) &C.void {
c := char(_c) mut s_ := unsafe { &char(s) }
mut s := unsafe { &char(_s) }
for i in 0 .. int(n) { for i in 0 .. int(n) {
unsafe { unsafe {
s[i] = c s_[i] = char(c)
} }
} }
return s return s
} }
[unsafe] [unsafe]
fn memmove(dest &byte, src &byte, n int) &byte { fn memmove(dest &C.void, src &C.void, n size_t) &C.void {
mut temp_buf := unsafe { malloc(n) } dest_ := unsafe { &byte(dest) }
src_ := unsafe { &byte(src) }
mut temp_buf := unsafe { malloc(int(n)) }
for i in 0 .. int(n) { for i in 0 .. int(n) {
unsafe { unsafe {
temp_buf[i] = src[i] temp_buf[i] = src_[i]
} }
} }
for i in 0 .. int(n) { for i in 0 .. int(n) {
unsafe { unsafe {
dest[i] = temp_buf[i] dest_[i] = temp_buf[i]
} }
} }
unsafe { free(temp_buf) } unsafe { free(temp_buf) }
@ -75,23 +79,25 @@ fn memmove(dest &byte, src &byte, n int) &byte {
[export: 'calloc'] [export: 'calloc']
[unsafe] [unsafe]
fn __calloc(nmemb int, size int) &byte { fn __calloc(nmemb size_t, size size_t) &C.void {
new_area := unsafe { malloc(nmemb * size) } new_area := unsafe { malloc(int(nmemb) * int(size)) }
unsafe { memset(new_area, 0, nmemb * size) } unsafe { memset(new_area, 0, nmemb * size) }
return new_area return new_area
} }
fn getchar() int { fn getchar() int {
x := byte(0) x := byte(0)
sys_read(C.stdin, &x, 1) sys_read(0, &x, 1)
return int(x) return int(x)
} }
fn memcmp(a &byte, b &byte, n int) int { fn memcmp(a &C.void, b &C.void, n size_t) int {
a_ := unsafe { &byte(a) }
b_ := unsafe { &byte(b) }
for i in 0 .. int(n) { for i in 0 .. int(n) {
if unsafe { a[i] != b[i] } { if unsafe { a_[i] != b_[i] } {
unsafe { unsafe {
return a[i] - b[i] return a_[i] - b_[i]
} }
} }
} }
@ -100,7 +106,7 @@ fn memcmp(a &byte, b &byte, n int) int {
[export: 'free'] [export: 'free']
[unsafe] [unsafe]
fn __free(ptr &byte) { fn __free(ptr &C.void) {
err := mm_free(ptr) err := mm_free(ptr)
if err != .enoerror { if err != .enoerror {
eprintln('free error:') eprintln('free error:')
@ -112,7 +118,7 @@ fn vsprintf(str &char, format &char, ap &byte) int {
panic('vsprintf(): string interpolation is not supported in `-freestanding`') panic('vsprintf(): string interpolation is not supported in `-freestanding`')
} }
fn vsnprintf(str &char, size int, format &char, ap &byte) int { fn vsnprintf(str &char, size size_t, format &char, ap &byte) int {
panic('vsnprintf(): string interpolation is not supported in `-freestanding`') panic('vsnprintf(): string interpolation is not supported in `-freestanding`')
} }
@ -128,3 +134,17 @@ fn bare_print(buf &byte, len u64) {
fn bare_eprint(buf &byte, len u64) { fn bare_eprint(buf &byte, len u64) {
sys_write(2, buf, len) sys_write(2, buf, len)
} }
fn bare_panic(msg string) {
println('V panic' + msg)
exit(1)
}
fn bare_backtrace() string {
return 'backtraces are not available with `-freestanding`'
}
[export: 'exit']
fn __exit(code int) {
sys_exit(code)
}

View File

@ -735,50 +735,17 @@ typedef void (*MapFreeFn)(voidptr);
c_common_macros + c_common_macros +
' '
#ifndef exit
#define exit(rc) sys_exit(rc)
void sys_exit (int);
#endif
#define stdin 0
#define stdout 1
#define stderr 2
#define _VFREESTANDING #define _VFREESTANDING
typedef long unsigned int size_t; typedef long unsigned int size_t;
// Memory allocation related headers // Memory allocation related headers
// void *malloc(int size); void *malloc(size_t size);
byte *calloc(int nitems, int size); void *calloc(size_t nitems, size_t size);
byte *realloc(byte *ptr, int size); void *realloc(void *ptr, size_t size);
byte *memcpy(byte *dest, byte *src, int n); void *memcpy(void *dest, void *src, size_t n);
byte *memset(byte *s, int c, int n); void *memset(void *s, int c, size_t n);
byte *memmove(byte *dest, byte *src, int n); void *memmove(void *dest, void *src, size_t n);
// Backtrace headers
int backtrace(void **buffer, int size);
char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
// I/O related headers
typedef void FILE;
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int getchar(void);
int ungetc(int c, FILE *stream);
// char manipulation headers
int toupper(int c);
int tolower(int c);
// int toupper_l(int c, locale_t locale);
// int tolower_l(int c, locale_t locale);
int isatty(int fd);
// varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky // varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky
typedef __builtin_va_list va_list; typedef __builtin_va_list va_list;
@ -804,6 +771,5 @@ static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
return memdup(src, sz); return memdup(src, sz);
} }
' + ' + c_wyhash
c_wyhash
) )