summaryrefslogtreecommitdiff
path: root/miniany/libc-freestanding.c
diff options
context:
space:
mode:
Diffstat (limited to 'miniany/libc-freestanding.c')
-rw-r--r--miniany/libc-freestanding.c145
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 );
+}