/* * minimal freestanding C library * * works for IA-32 and Linux, uses old INT 80h software interrupts * for system calls. * */ #include 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; } static void strreverse( char *s ) { char *end = s + strlen( s ) - 1; while( s < end ) { *s ^= *end; *end ^= *s; *s ^= *end; s++; end--; } } char *itoa( int v, char *s, int base ) { static char digit[] = "0123456789ABCDEF"; int sign = 0; char *p = s; if( base < 2 || base > 16 ) { return NULL; } if( v < 0 ) { v = -v; sign = 1; } do { *p++ = digit[v % base]; } while( ( v /= base ) > 0 ); if( sign ) { *p++ = '-'; } *p = '\0'; strreverse( s ); return s; } int putint( int i ) { char buf[17]; itoa( i, buf, 10 ); print_string( buf ); return i; } int putstring( char *s ) { print_string( s ); return 0; } int putnl( ) { putchar( '\n' ); return 0; } void exit( int status ) { syscall1( SYSCALL_EXIT, status ); }