From 7d356b1ddab0150b7347a5952e3bff2a04704fd4 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Thu, 13 Jul 2017 20:09:53 +0200 Subject: added an exit function added Linux syscall stubs for exit and write adapted all tests added a printf test made stdio work on Linux or AbaOs syscalls --- doc/LINKS.TODO | 3 ++ src/Makefile | 5 ++- src/libc/stdio.c | 93 +++++++++++++++++++++++++++++++++++----------- src/libc/stdio.h | 4 ++ src/libc/stdlib.c | 20 +++++++++- src/libc/stdlib.h | 3 +- tests/libc/Makefile | 70 +++++++++++++++++++++++----------- tests/libc/kernel_stub.asm | 48 ++++++++++++++++++++++++ tests/libc/kernel_stub.c | 8 +++- tests/libc/kernel_stub.h | 27 ++++++++++++++ tests/libc/test_abort.c | 6 +++ tests/libc/test_itoa.c | 14 +++---- tests/libc/test_malloc.c | 6 +-- tests/libc/test_printf.c | 15 ++++++++ tests/libc/test_strlcat.c | 11 +++--- tests/libc/test_strlcpy.c | 7 ++-- 16 files changed, 274 insertions(+), 66 deletions(-) create mode 100644 tests/libc/kernel_stub.asm create mode 100644 tests/libc/kernel_stub.h create mode 100644 tests/libc/test_abort.c create mode 100644 tests/libc/test_printf.c diff --git a/doc/LINKS.TODO b/doc/LINKS.TODO index 092c620..89f7ce8 100644 --- a/doc/LINKS.TODO +++ b/doc/LINKS.TODO @@ -99,3 +99,6 @@ http://webserver2.tecgraf.puc-rio.br/iup/ linker: https://stackoverflow.com/questions/26143123/how-do-i-ensure-the-entry-function-at-a-fixed-address-of-bare-metal-arm + +Linux: +https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/ diff --git a/src/Makefile b/src/Makefile index 4192fd1..b4ceff1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,7 @@ CC := gcc -INCLUDES = -DOS_ABAOS -I. -Ilibc -Ihardware -Idrivers -Idrivers/hdi -Idrivers/hdi/ps2 -Idrivers/video -Ikernel -Igui -CFLAGS := -std=c99 -m32 -march=i486 -ffreestanding -O0 -g -Werror $(INCLUDES) +DEFINES = -DOS_ABAOS +INCLUDES = -I. -Ilibc -Ihardware -Idrivers -Idrivers/hdi -Idrivers/hdi/ps2 -Idrivers/video -Ikernel -Igui +CFLAGS := -std=c99 -m32 -march=i486 -ffreestanding -O0 -g -Werror $(INCLUDES) $(DEFINES) LD := ld NASMFLAGS := -f elf32 NASM := nasm diff --git a/src/libc/stdio.c b/src/libc/stdio.c index 07a047e..631cfbb 100644 --- a/src/libc/stdio.c +++ b/src/libc/stdio.c @@ -3,17 +3,70 @@ #include "stdlib.h" #include "string.h" +#ifdef OS_ABAOS +#include "kernel.h" +#endif + +#ifdef OS_ABAOS console_t *stdio_console = NULL; +#endif -int puts( const char *s ) +static void print_string( const char *s ); +static void print_char( const char c ); +static void print_newline( void ); + +#ifdef OS_ABAOS +static void print_string( const char *s ) { if( stdio_console == NULL ) { - return EOF; + kernel_panic( "stdio_console not set!" ); } - + console_put_string( stdio_console, s ); +} + +static void print_char( const char c ) +{ + if( stdio_console == NULL ) { + kernel_panic( "stdio_console not set!" ); + } + + console_put_char( stdio_console, c ); +} + +static void print_newline( void ) +{ + if( stdio_console == NULL ) { + kernel_panic( "stdio_console not set!" ); + } + console_put_newline( stdio_console ); - +} +#endif + +#ifdef OS_LINUX +static void print_string( const char *s ) +{ + syscall3( __NR_write, STDOUT_FILENO, (long)s, strlen( s ) ); +} + +static void print_char( const char c ) +{ + char s[2]; s[0] = c; + syscall3( __NR_write, STDOUT_FILENO, (long)s, 1 ); +} + +static void print_newline( void ) +{ + syscall3( __NR_write, STDOUT_FILENO, (long)"\n", 1 ); +} +#endif + +int puts( const char *s ) +{ + print_string( s ); + print_newline( ); + return 1; } @@ -32,35 +85,31 @@ int vprintf( const char *format, va_list args ) { const char *s = format; int n = 0; - - if( stdio_console == NULL ) { - return -1; - } while( *s != '\0' ) { switch( *s ) { case '\n': - console_put_newline( stdio_console ); + print_newline( ); n++; break; case '%': s++; if( *s == '\0' ) { - console_put_string( stdio_console, "" ); - console_put_newline( stdio_console ); + print_string( "" ); + print_newline( ); return -1; } switch( *s ) { case '%': - console_put_char( stdio_console, '%' ); + print_char( '%' ); break; case 'X': { char buf[19]; itoa( va_arg( args, int ), (char *)buf, 16 ); - console_put_string( stdio_console, buf ); + print_string( buf ); n += strlen( buf ); } break; @@ -68,30 +117,30 @@ int vprintf( const char *format, va_list args ) case 'd': { char buf[19]; itoa( va_arg( args, int ), (char *)buf, 10 ); - console_put_string( stdio_console, buf ); + print_string( buf ); n += strlen( buf ); } break; case 'c': - console_put_char( stdio_console, va_arg( args, int ) ); + print_char( va_arg( args, int ) ); break; case 's': - console_put_string( stdio_console, va_arg( args, const char * ) ); + print_string( va_arg( args, const char * ) ); break; default: - console_put_string( stdio_console, "" ); - console_put_newline( stdio_console ); + print_string( "" ); + print_newline( ); } break; default: - console_put_char( stdio_console, *s ); + print_char( *s ); n++; } s++; @@ -100,7 +149,9 @@ int vprintf( const char *format, va_list args ) return n; } +#ifdef OS_ABAOS void __stdio_set_console( console_t *console ) { stdio_console = console; } +#endif diff --git a/src/libc/stdio.h b/src/libc/stdio.h index 24632f6..33d7946 100644 --- a/src/libc/stdio.h +++ b/src/libc/stdio.h @@ -9,6 +9,10 @@ #include "console.h" #endif +#ifdef OS_LINUX +#include "kernel_stub.h" +#endif + #define EOF (-1) int puts( const char *s ); diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c index d7d4331..b4c2d84 100644 --- a/src/libc/stdlib.c +++ b/src/libc/stdlib.c @@ -48,11 +48,29 @@ char *itoa( int v, char *s, int base ) return s; } -void abort( void ) +void __attribute__( ( noreturn ) ) exit( int status ) +{ +#ifdef OS_ABAOS + // TODO: this should be done on process level, terminating + // the process (by signalling SIGABRT for instance) + kernel_panic( "exited with exit code %d", status ); +#endif +#ifdef OS_LINUX + syscall1( __NR_exit, status ); +#endif + + // make gcc happy ("error: ‘noreturn’ function does return") + for( ;; ); +} + +void __attribute__( ( noreturn ) ) abort( void ) { // TODO: this should be done on process level, terminating // the process (by signalling SIGABRT for instance) kernel_panic( "aborted" ); + + // make gcc happy ("error: ‘noreturn’ function does return") + for( ;; ); } // TODO: we should have a global memory manager and one per diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h index 9ff28a3..5b2521f 100644 --- a/src/libc/stdlib.h +++ b/src/libc/stdlib.h @@ -7,7 +7,8 @@ char *itoa( int v, char *s, int base ); -void abort( void ); +void __attribute__( (noreturn ) ) exit( int status ); +void __attribute__( (noreturn ) ) abort( void ); void *malloc( size_t size ); void free( void *p ); diff --git a/tests/libc/Makefile b/tests/libc/Makefile index 43620d7..59fa715 100644 --- a/tests/libc/Makefile +++ b/tests/libc/Makefile @@ -1,53 +1,79 @@ CC := gcc -CFLAGS := -std=c99 -m32 -ffreestanding -O0 -g -Wall -Werror -INCLUDES = -I../../src/libc -I../../src/kernel -LD := ld +DEFINES = -DOS_LINUX +INCLUDES = -I. -I../../src/libc -I../../src/kernel +CFLAGS := -std=c99 -m32 -ffreestanding -O0 -g -Wall -Werror $(INCLUDES) $(DEFINES) +# tcc misses crt1.o from gcc?! and fails with _start symbol missing on -nostdlib, +# this seems very wrong.. +# TODO: for now test sanity of library tests with gcc and enabling -nostdlib +#LDFLAGS := -nostdlib +NASMFLAGS := -f elf32 +NASM := nasm all: test -test_strlcpy: test_strlcpy.o ../../src/libc/string.o - $(CC) -o test_strlcpy test_strlcpy.o ../../src/libc/string.o +test_strlcpy: test_strlcpy.o ../../src/libc/string.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) -o test_strlcpy test_strlcpy.o ../../src/libc/string.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o test_strlcpy.o: test_strlcpy.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o test_strlcpy.o test_strlcpy.c + $(CC) $(CFLAGS) -c -o test_strlcpy.o test_strlcpy.c -test_strlcat: test_strlcat.o ../../src/libc/string.o - $(CC) -o test_strlcat test_strlcat.o ../../src/libc/string.o +test_strlcat: test_strlcat.o ../../src/libc/string.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) $(LDFLAGS) -o test_strlcat test_strlcat.o ../../src/libc/string.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o test_strlcat.o: test_strlcat.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o test_strlcat.o test_strlcat.c + $(CC) $(CFLAGS) -c -o test_strlcat.o test_strlcat.c -test_itoa: test_itoa.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o - $(CC) -o test_itoa test_itoa.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o +test_itoa: test_itoa.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) $(LDFLAGS) -o test_itoa test_itoa.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o test_itoa.o: test_itoa.c ../../src/libc/stdlib.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o test_itoa.o test_itoa.c + $(CC) $(CFLAGS) -c -o test_itoa.o test_itoa.c -test_malloc: test_malloc.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o - $(CC) -o test_malloc test_malloc.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o +test_malloc: test_malloc.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) $(LDFLAGS) -o test_malloc test_malloc.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o test_malloc.o: test_malloc.c ../../src/libc/stdlib.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o test_malloc.o test_malloc.c + $(CC) $(CFLAGS) -c -o test_malloc.o test_malloc.c + +test_printf: test_printf.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) $(LDFLAGS) -o test_printf test_printf.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + +test_printf.o: test_printf.c ../../src/libc/stdlib.h + $(CC) $(CFLAGS) -c -o test_printf.o test_printf.c + +test_abort: test_abort.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(CC) $(LDFLAGS) -o test_abort test_abort.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + +test_abort.o: test_abort.c ../../src/libc/stdlib.h + $(CC) $(CFLAGS) -c -o test_abort.o test_abort.c ../../src/libc/string.o: ../../src/libc/string.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o ../../src/libc/string.o ../../src/libc/string.c + $(CC) $(CFLAGS) -c -o ../../src/libc/string.o ../../src/libc/string.c ../../src/libc/stdlib.o: ../../src/libc/stdlib.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o ../../src/libc/stdlib.o ../../src/libc/stdlib.c + $(CC) $(CFLAGS) -c -o ../../src/libc/stdlib.o ../../src/libc/stdlib.c + +../../src/libc/stdio.o: ../../src/libc/stdio.c + $(CC) $(CFLAGS) -c -o ../../src/libc/stdio.o ../../src/libc/stdio.c ../../src/kernel/memorymanagement.o: ../../src/kernel/memorymanagement.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o ../../src/kernel/memorymanagement.o ../../src/kernel/memorymanagement.c + $(CC) $(CFLAGS) -c -o ../../src/kernel/memorymanagement.o ../../src/kernel/memorymanagement.c kernel_stub.o: kernel_stub.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o kernel_stub.o kernel_stub.c + $(CC) $(CFLAGS) -c -o kernel_stub.o kernel_stub.c + +kernel_stub_asm.o: kernel_stub.asm + $(NASM) kernel_stub.asm $(NASMFLAGS) -o kernel_stub_asm.o -test: test_strlcpy test_strlcat test_itoa test_malloc +test: test_strlcpy test_strlcat test_itoa test_malloc test_abort test_printf ./test_strlcpy ./test_strlcat ./test_itoa ./test_malloc + ./test_printf + -./test_abort clean: - -rm -f test_strlcpy test_strlcat test_itoa test_malloc - -rm -f ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o + -rm -f test_strlcpy test_strlcat test_itoa test_malloc test_printf test_abort + -rm -f ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o -rm -f *.o diff --git a/tests/libc/kernel_stub.asm b/tests/libc/kernel_stub.asm new file mode 100644 index 0000000..c9335a8 --- /dev/null +++ b/tests/libc/kernel_stub.asm @@ -0,0 +1,48 @@ +[bits 32] + +global syscall0 +global syscall1 +global syscall2 +global syscall3 + +; long syscall1( long n ); +syscall0: + push ebp + mov ebp, esp + mov eax, [ebp+8] + int 0x80 + leave + ret + +; long syscall1( long n, long a1 ); +syscall1: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov ebx, [ebp+12] + int 0x80 + leave + ret + +; long syscall2( long n, long a1, long a2 ); +syscall2: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov ebx, [ebp+12] + mov ecx, [ebp+16] + int 0x80 + leave + ret + +; long syscall3( long n, long a1, long a2, long a3 ); +syscall3: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov ebx, [ebp+12] + mov ecx, [ebp+16] + mov edx, [ebp+20] + int 0x80 + leave + ret diff --git a/tests/libc/kernel_stub.c b/tests/libc/kernel_stub.c index c859be0..610c3d3 100644 --- a/tests/libc/kernel_stub.c +++ b/tests/libc/kernel_stub.c @@ -3,6 +3,12 @@ #include "stdio.h" #include "stdlib.h" +// abaos has a kernel_panic function +// TODO: we should not need this stub, rather, libc functions should +// use other means to abort the process (e.g. with abort), then the +// kernel should catch this exception and issue the kernel_panic itself. +// anyway: the kernel has to decide whether it dies in panic or it +// kills the culprid child an merely goes his way.. void kernel_panic( const char *format, ... ) { (void)printf( "\n*** KERNEL PANIC ***\n" ); @@ -13,6 +19,6 @@ void kernel_panic( const char *format, ... ) va_end( args ); puts( "" ); - abort( ); + exit( 255 ); } diff --git a/tests/libc/kernel_stub.h b/tests/libc/kernel_stub.h new file mode 100644 index 0000000..467ad20 --- /dev/null +++ b/tests/libc/kernel_stub.h @@ -0,0 +1,27 @@ +#ifndef KERNEL_STUB_H +#define KERNEL_STUB_H + +// abaos has a kernel_panic function +// TODO: we should not need this stub, rather, libc functions should +// use other means to abort the process (e.g. with abort), then the +// kernel should catch this exception and issue the kernel_panic itself. +// anyway: the kernel has to decide whether it dies in panic or it +// kills the culprid child an merely goes his way.. +void kernel_panic( const char *format, ... ); + +// definitions to emulate kernel functions by calling Linux kernel +// syscalls directly (careful: works for 32-bit Intel only!) + +// those are defined in sys/syscall.h +#define __NR_exit 1 +#define __NR_write 4 + +// defined in unistd.h +#define STDOUT_FILENO 1 + +long syscall0( long n ); +long syscall1( long n, long a1 ); +long syscall2( long n, long a1, long a2 ); +long syscall3( long n, long a1, long a2, long a3 ); + +#endif diff --git a/tests/libc/test_abort.c b/tests/libc/test_abort.c new file mode 100644 index 0000000..da5c0f2 --- /dev/null +++ b/tests/libc/test_abort.c @@ -0,0 +1,6 @@ +#include "stdlib.h" + +int main( void ) +{ + abort( ); +} diff --git a/tests/libc/test_itoa.c b/tests/libc/test_itoa.c index 837b77a..837fd01 100644 --- a/tests/libc/test_itoa.c +++ b/tests/libc/test_itoa.c @@ -9,26 +9,26 @@ int main( void ) // simple conversion without sign res = itoa( 568876, buf, 10 ); - if( strcmp( buf, "568876" ) ) return 1; + if( strcmp( buf, "568876" ) ) exit( 1 ); // test if the returned pointer points to the buffer - if( strcmp( res, buf ) ) return 1; + if( strcmp( res, buf ) ) exit( 1 ); // conversion with sign res = itoa( -568876, buf, 10 ); - if( strcmp( buf, "-568876" ) ) return 1; + if( strcmp( buf, "-568876" ) ) exit( 1 ); // convert upper limit res = itoa( INT_MAX, buf, 10 ); - if( strcmp( buf, "2147483647" ) ) return 1; + if( strcmp( buf, "2147483647" ) ) exit( 1 ); // convert lower limit res = itoa( INT_MIN+1, buf, 10 ); - if( strcmp( buf, "-2147483647" ) ) return 1; + if( strcmp( buf, "-2147483647" ) ) exit( 1 ); // convert to hex res = itoa( 568876, buf, 16 ); - if( strcmp( buf, "8AE2C" ) ) return 1; + if( strcmp( buf, "8AE2C" ) ) exit( 1 ); - return 0; + exit( 0 ); } diff --git a/tests/libc/test_malloc.c b/tests/libc/test_malloc.c index 0f74fad..aaff2da 100644 --- a/tests/libc/test_malloc.c +++ b/tests/libc/test_malloc.c @@ -17,8 +17,8 @@ int main( void ) s = (char *)malloc( strlen( s1 ) + 1 ); size_t n = strlcpy( s, s1, strlen( s1 ) + 1 ); - if( n != 11 ) return 1; - if( strcmp( s, s1 ) != 0 ) return 1; + if( n != 11 ) exit( 1 ); + if( strcmp( s, s1 ) != 0 ) exit( 1 ); - return 0; + exit( 0 ); } diff --git a/tests/libc/test_printf.c b/tests/libc/test_printf.c new file mode 100644 index 0000000..d2fc849 --- /dev/null +++ b/tests/libc/test_printf.c @@ -0,0 +1,15 @@ +#include "string.h" +#include "stdlib.h" +#include "stdio.h" + +int main( void ) +{ + char *s = "test_string"; + int i = 47; + char c = 'X'; + + printf( "string '%s', decimal %d, hex 0x%X, character '%c'\n", + s, i, i, c ); + + exit( 0 ); +} diff --git a/tests/libc/test_strlcat.c b/tests/libc/test_strlcat.c index 074cb98..5a1bfc9 100644 --- a/tests/libc/test_strlcat.c +++ b/tests/libc/test_strlcat.c @@ -1,4 +1,5 @@ #include "string.h" +#include "stdlib.h" int main( void ) { @@ -9,11 +10,11 @@ int main( void ) *d = '\0'; n = strlcat( d, s1, 15 ); - if( n != 11 ) return 1; - if( strcmp( d, s1 ) != 0 ) return 1; + if( n != 11 ) exit( 1 ); + if( strcmp( d, s1 ) != 0 ) exit( 1 ); n = strlcat( d, s2, 15 ); - if( n != 14 ) return 1; - if( strcmp( d, "test_stringapp" ) != 0 ) return 1; + if( n != 14 ) exit( 1 ); + if( strcmp( d, "test_stringapp" ) != 0 ) exit( 1 ); - return 0; + exit( 0 ); } diff --git a/tests/libc/test_strlcpy.c b/tests/libc/test_strlcpy.c index a23a5bc..ac7acf9 100644 --- a/tests/libc/test_strlcpy.c +++ b/tests/libc/test_strlcpy.c @@ -1,4 +1,5 @@ #include "string.h" +#include "stdlib.h" int main( void ) { @@ -8,8 +9,8 @@ int main( void ) // copy into too small string n = strlcpy( d, s, 4 ); - if( n != 11 ) return 1; - if( strcmp( d, "tes" ) ) return 1; + if( n != 11 ) exit( 1 ); + if( strcmp( d, "tes" ) ) exit( 1 ); - return 0; + exit( 0 ); } -- cgit v1.2.3-54-g00ecf