diff options
Diffstat (limited to 'miniany/libc-freestanding.c')
-rw-r--r-- | miniany/libc-freestanding.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/miniany/libc-freestanding.c b/miniany/libc-freestanding.c new file mode 100644 index 0000000..b4e48f8 --- /dev/null +++ b/miniany/libc-freestanding.c @@ -0,0 +1,145 @@ +/* + * minimal freestanding C library + * + * works for IA-32 and Linux, uses old INT 80h software interrupts + * for system calls. + * + */ + +int strlen( char *s ) +{ + char *p; + + p = s; + while( *p != '\0' ) { + p++; + } + + return p - s; +} + +enum { + EXIT_SUCCESS = 0, + EXIT_FAILURE = 1 +}; + +enum { + SYSCALL_EXIT = 1, + SYSCALL_READ = 3, + SYSCALL_WRITE = 4 +}; + +int errno; + +static __attribute__((noinline)) int syscall1( int id, int arg0 ) +{ + int retval; + + __asm__ volatile( "\ + push %%ebx\n\ + mov %1, %%eax\n\ + mov %2, %%ebx\n\ + int $0x80\n\ + mov %%eax, %0\n\ + pop %%ebx\n" : "=m"( retval ) : "m"( id ), "m"( arg0 ) + : "eax", "ebx" ); + + if( retval < 0 ) { + errno = -retval; + return -1; + } + + return retval; +} + +static __attribute__((noinline)) int syscall3( int id, int arg0, int arg1, int arg2 ) +{ + int retval; + + __asm__ volatile( "\ + push %%ebx\n\ + push %%ecx\n\ + push %%edx\n\ + mov %1, %%eax\n\ + mov %2, %%ebx\n\ + mov %3, %%ecx\n\ + mov %4, %%edx\n\ + int $0x80\n\ + mov %%eax, %0\n\ + pop %%edx\n\ + pop %%ecx\n\ + pop %%ebx\n" : "=m"( retval ) : "m"( id ), "m"( arg0 ), "m"( arg1 ), "m"( arg2 ) + : "eax", "ebx", "ecx", "edx" ); + + if( retval < 0 ) { + errno = -retval; + return -1; + } + + return retval; +} + +enum { + STDIN_FILENO = 0, + STDOUT_FILENO = 1, + STDERR_FILENO = 2 +}; + +static void print_char( int fd, int c ) +{ + char s[1]; + s[0] = c; + syscall3( SYSCALL_WRITE, fd, (int)s, 1 ); +} + +static void print_string( char *s ) +{ + syscall3( SYSCALL_WRITE, STDOUT_FILENO, (int)s, strlen( s ) ); +} + +static void print_newline( void ) +{ + print_char( STDOUT_FILENO, '\n' ); +} + +static int read_string( int fd, char *buf, int size ) +{ + return syscall3( SYSCALL_READ, fd, (int)buf, size ); +} + +enum { + EOF = -1 +}; + +int puts( char *s ) +{ + print_string( s ); + print_newline( ); + + return 1; +} + +int getchar( ) +{ + int res; + char buf[1]; + + res = read_string( STDIN_FILENO, buf, 1 ); + if( res == 0 ) { + return EOF; + } + + return buf[0]; +} + +int putchar( int c ) +{ + print_char( STDOUT_FILENO, c ); + + return c; +} + +void exit( int status ) +{ + syscall1( SYSCALL_EXIT, status ); +} |