commit b8f04aa6fc6abab81fb8af1f0a0b58994fe2df25
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Fri, 6 Dec 2024 16:15:41 +0000
Initial working version in AT&T syntax
Diffstat:
| A | Tupfile | | | 7 | +++++++ |
| A | Tupfile.ini | | | 0 | |
| A | crt0.s | | | 12 | ++++++++++++ |
| A | crt1.c | | | 14 | ++++++++++++++ |
| A | echo.c | | | 52 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | syscall.h | | | 14 | ++++++++++++++ |
| A | syscall.s | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 199 insertions(+), 0 deletions(-)
diff --git a/Tupfile b/Tupfile
@@ -0,0 +1,7 @@
+CFLAGS = -Os -fno-asynchronous-unwind-tables
+LDFLAGS = -static -nostartfiles -nostdlib -Xlinker --gc-sections
+
+: foreach *.c *.s |> cc $(CFLAGS) -c -o %o %f |> x86_64/%B.o {objs.x86_64}
+: {objs.x86_64} |> cc $(LDFLAGS) -o %o %f |> echo.x86_64
+
+.gitignore
diff --git a/Tupfile.ini b/Tupfile.ini
diff --git a/crt0.s b/crt0.s
@@ -0,0 +1,12 @@
+.global _start
+
+.text
+
+_start: # _start is the entry point known to the linker
+ xor %ebp, %ebp # effectively RBP := 0, mark the end of stack frames
+ mov (%rsp), %edi # get argc from the stack (implicitly zero-extended to 64-bit)
+ lea 8(%rsp), %rsi # take the address of argv from the stack
+ lea 16(%rsp,%rdi,8), %rdx # take the address of envp from the stack
+ xor %eax, %eax # per ABI and compatibility with icc
+ jmp start # %edi, %rsi, %rdx are the three args (of which first two are C standard) to main
+
diff --git a/crt1.c b/crt1.c
@@ -0,0 +1,14 @@
+#include "syscall.h"
+
+extern char __bss_start[], _end[];
+extern int main(int, char**, char**);
+
+__attribute__((noreturn))
+void start(int argc, char* argv[], char* envp[])
+{
+ for (char* p = __bss_start; p < _end; ++p)
+ *p = 0;
+
+ exit(main(argc, argv, envp));
+ __builtin_trap();
+}
diff --git a/echo.c b/echo.c
@@ -0,0 +1,52 @@
+#include "syscall.h"
+
+static char buf[0x1000];
+static unsigned bufsize;
+
+static void putflush()
+{
+ if (bufsize && write(1, buf, bufsize) != bufsize)
+ exit(1);
+ bufsize = 0;
+}
+
+static void putch(char c)
+{
+ buf[bufsize++] = c;
+ if (c == '\n' || bufsize == sizeof buf)
+ putflush();
+}
+
+static void putstr(char const* s)
+{
+ while(*s)
+ putch(*s++);
+}
+/*
+static void* sbrk(unsigned size)
+{
+ static void* end;
+
+ if (!end)
+ end = brk(NULL);
+
+ end += size;
+
+ if (brk(end) != end)
+ exit(1);
+
+ return end;
+}
+*/
+int main(int argc, char* argv[])
+{
+// sbrk(0);
+ if (argc > 1)
+ putstr(argv[1]);
+ for (int i = 2; i < argc; ++i)
+ {
+ putch(' ');
+ putstr(argv[i]);
+ }
+ putch('\n');
+}
diff --git a/syscall.h b/syscall.h
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+extern int read(int fd, char* data, size_t count);
+extern int write(int fd, char const* data, size_t count);
+extern int open(char const* name, int flags, int mode);
+extern int close(int fd);
+extern void* mmap(void* addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
+
+extern void* brk(void* new_brk);
+
+__attribute__((noreturn))
+extern void exit(int error_code);
+
+extern int ftruncate(int fd, unsigned long length);
diff --git a/syscall.s b/syscall.s
@@ -0,0 +1,100 @@
+.macro syscall3, num, name
+.global \name
+.section .text.\name
+\name:
+ push %r11
+ push %rcx
+ mov $\num, %rax
+ syscall
+ pop %rcx
+ pop %r11
+ ret
+.endm
+
+.macro syscall6, num, name
+.global \name
+.section .text.\name
+\name:
+ push %r11
+ mov $\num, %rax
+ mov %rcx, %r10
+ syscall
+ pop %r11
+ ret
+.endm
+
+.text
+.global exit
+
+syscall3 0 read
+syscall3 1 write
+syscall3 2 open
+syscall3 3 close
+syscall3 4 stat
+syscall3 5 fstat
+syscall3 6 lstat
+syscall3 7 poll
+syscall3 8 lseek
+syscall6 9 mmap
+syscall3 10 mprotect
+syscall3 11 munmap
+syscall3 12 brk
+syscall6 13 rt_sigaction
+syscall6 14 rt_sigprocmask
+syscall3 15 rt_sigreturn
+syscall3 16 ioctl
+syscall6 17 pread64
+syscall6 18 pwrite64
+syscall3 19 readv
+syscall3 20 writev
+syscall3 21 access
+syscall3 22 pipe
+syscall6 23 select
+syscall3 24 yield
+syscall6 25 mremap
+syscall3 26 msync
+syscall3 27 mincore
+syscall3 28 madvise
+syscall3 29 shmget
+syscall3 30 shmat
+syscall3 31 shmctl
+syscall3 32 dup
+syscall3 33 dup2
+syscall3 34 pause
+syscall3 35 nanosleep
+syscall3 36 getitimer
+syscall3 37 alarm
+syscall3 38 setitimer
+syscall3 39 getpid
+syscall6 40 sendfile
+syscall3 41 socket
+syscall3 42 connect
+syscall3 43 accept
+syscall6 44 sendto
+syscall6 45 recvfrom
+syscall3 46 sendmsg
+syscall3 47 recvmsg
+syscall3 48 shutdown
+syscall3 49 bind
+syscall3 50 listen
+syscall3 51 getsockname
+syscall3 52 getpeername
+syscall3 53 socketpair
+syscall6 54 setsockopt
+syscall6 55 getsockopt
+syscall3 56 clone
+syscall3 57 fork
+syscall3 58 vfork
+syscall3 59 execve
+
+.section .text.exit
+exit: mov $60, %rax
+ syscall
+
+syscall6 61 wait4
+syscall3 62 kill
+syscall3 63 uname
+syscall3 64 semget
+syscall3 65 semop
+
+syscall3 77 ftruncate