#define START "_start" #include #include #include #include #include "common.h" enum { flush_on_newline = 1 }; int errno = 0; char *progname; static long sysret(unsigned long r) { if (r > -4096UL) { errno = -r; return -1; } return r; } void exit(int code) { __syscall1(__NR_exit, code); } static void *brk(void *addr) { return (void *)__syscall1(__NR_brk, (long)addr); } int write(int fd, char *buf, int len) { return sysret(__syscall3(__NR_write, fd, (long)buf, len)); } int read(int fd, char *buf, int len) { return sysret(__syscall3(__NR_read, fd, (long)buf, len)); } int open(char *fname, int flags, int mode) { int o_largefile = 0100000; return sysret(__syscall3(__NR_open, (long)fname, flags|o_largefile, mode)); } int stat(char *fname, struct stat *st) { return sysret(__syscall2(__NR_stat, (long)fname, (long)st)); } int fstat(int fd, struct stat *st) { return sysret(__syscall2(__NR_fstat, (long)fd, (long)st)); } int close(int fd) { return sysret(__syscall1(__NR_close, fd)); } void *mmap(char *addr, unsigned long length, int prot, int flags, int fd, unsigned long offset) { return (void*)sysret(__syscall6(__NR_mmap, (long)addr, length, prot, flags, fd, offset)); } int munmap(char *addr, int length) { return sysret(__syscall2(__NR_munmap, (long)addr, length)); } #define MREMAP_MAYMOVE 1 int mremap(void *old_addr, unsigned long old_size, unsigned long new_size, int flags, void *new_addr) { return sysret(__syscall5(__NR_mremap, (long)old_addr, old_size, new_size, flags, (long)new_addr)); } int strzlen(char *s) { char *sc = s; for (; *s; ++s) ; return s - sc; } int strzeq(char *s1, char *s2) { for (; *s1 && *s1 == *s2; ++s1, ++s2) ; return *s1 == 0 && *s2 == 0; } int streq(struct str *s1, struct str *s2) { int i; if (s1->end - s1->start != s2->end - s2->start) return 0; for (i = 0; s1->start + i < s1->end; ++i) { if (s1->start[i] != s2->start[i]) return 0; } return 1; } void memmove(char *dest, char *src, int len) { int i; if (dest < src) { for (i = 0; i < len; ++i) dest[i] = src[i]; } else { for (i = len - 1; i >= 0; --i) dest[i] = src[i]; } } void memcpy(void *dest, void *src, int len) { int i; char *d = dest; char *s = src; for (i = 0; i < len; ++i) d[i] = s[i]; } void memset(void *dest, char c, int len) { char *tmp = dest; for (; tmp < (char*)dest + len; ++tmp) *tmp = c; } #define E(e, s) [e] = s, char *estrings[256] = { #include "../src/errno/__strerror.h" }; #undef E void perror(char *s) { int idx = errno; if (errno > 256 || estrings[errno] == NULL) idx = 0; eprintf("%s: %s\n", s, estrings[idx]); } void syscall_error(char *fname) { perror(fname); hexit(1); } enum { buflen = 32 * 1024 }; struct iobuf { int fd; char buf[buflen]; int len; }; struct iobuf stdout = { 1 }; struct iobuf stderr = { 2 }; static void flush(struct iobuf *buf) { int ret = write(buf->fd, buf->buf, buf->len); if (ret != buf->len) { write(2, _S("some stdout/stderr error\n")); exit(3); } buf->len = 0; } static void putchar(struct iobuf *buf, char c) { if (buf->len == buflen) flush(buf); buf->buf[buf->len] = c; ++buf->len; if (flush_on_newline && c == '\n') flush(buf); } void hexit(int code) { flush(&stdout); flush(&stderr); exit(code); } static void print_int(struct iobuf *buf, int nsigned, int byte4, unsigned long n) { char tmpbuf[64]; char *p = tmpbuf; unsigned long k; if (nsigned) { if (byte4) { int tmp = n; if (tmp < 0) { putchar(buf, '-'); tmp = -tmp; } k = tmp; } else { if ((signed long)n < 0) { putchar(buf, '-'); n = -n; } k = n; } } else { k = n; } if (k == 0) { putchar(buf, '0'); return; } for (; k > 0; k /= 10) { *p = k % 10 + '0'; ++p; } for (--p;; --p) { putchar(buf, *p); if (p == tmpbuf) break; } } void print_strz(struct iobuf *buf, char *s) { for (; *s; ++s) putchar(buf, *s); } void print_str(struct iobuf *buf, struct str *s) { char *tmp = s->start; for (; tmp != s->end; ++tmp) putchar(buf, *tmp); } static void format(struct iobuf *buf, char c, va_list vl) { switch(c) { unsigned long arg; case '%': putchar(buf, '%'); break; case 'd': case 'u': arg = va_arg(vl, unsigned int); print_int(buf, c == 'd', 1, arg); break; case 'D': case 'U': arg = va_arg(vl, unsigned long); print_int(buf, c == 'D', 0, arg); break; case 's': print_strz(buf, va_arg(vl, char*)); break; case 'S': print_str(buf, va_arg(vl, struct str *)); break; case 'c': arg = va_arg(vl, int); putchar(buf, arg); break; default: write(2, _S("printf: unexpected format option \n")); hexit(2); } } static void __printf(struct iobuf *buf, char *s, va_list vl) { for (; *s; ++s) { if (*s == '%') { if (s[1] == 0) { write(2, _S("printf: nothing comes after '%'")); hexit(2); } format(buf, s[1], vl); ++s; } else { putchar(buf, *s); } } return; } void printf(char *fmt, ...) { va_list vl; va_start(vl, fmt); __printf(&stdout, fmt, vl); va_end(vl); } void evprintf(char *fmt, va_list vl) { print_strz(&stderr, progname); print_strz(&stderr, ": "); __printf(&stderr, fmt, vl); } void eprintf(char *fmt, ...) { va_list vl; va_start(vl, fmt); evprintf(fmt, vl); va_end(vl); } /* Memory management */ struct mem_buffer { char *cur, *end; char *saved; }; static struct mem_buffer mem_buf; static void mem_buffer_init() { mem_buf.cur = mem_buf.end = brk(NULL); mem_buf.saved = NULL; } void save_heap_offset() { if (mem_buf.saved != NULL) { eprintf("mem_buffer: offset already saved\n"); hexit(2); } mem_buf.saved = mem_buf.cur; } void restore_heap_offset() { if (mem_buf.saved == NULL) { eprintf("mem_buffer: no offset was saved\n"); hexit(2); } mem_buf.cur = mem_buf.saved; mem_buf.saved = NULL; } static int get_alignment(int n) { if (n >= 16) return 16; if (n >= 8) return 8; if (n >= 4) return 4; if (n >= 2) return 2; return 1; } static void mem_buf_grow(int size) { char *tmp; if (size < 128*1024) { size = 128*1024; } else { size *= 2; size &= -4096; } /*printf("Growing (%d)\n", size);*/ tmp = brk(mem_buf.end + size); if (tmp == mem_buf.end) { eprintf("mem_buf: unable to allocate memory\n"); hexit(1); } mem_buf.end = tmp; } #define ALIGN(v, align) \ (void*)(((unsigned long)(v) + (align) - 1ul) & -(align)) void *malloc(int size) { int align = get_alignment(size); char *tmp = ALIGN(mem_buf.cur, align); int diff = tmp + size - mem_buf.end; if (diff > 0) mem_buf_grow(diff); mem_buf.cur = tmp + size; return tmp; } int main(int argc, char **argv, char **envp); void _start_c(unsigned long *p) { int argc = p[0]; char **argv = (void *)(p + 1); char **envp = argv + argc + 1; progname = argv[0]; mem_buffer_init(); hexit(main(argc, argv, envp)); }