106 lines
2.9 KiB
C
106 lines
2.9 KiB
C
/* syscall.c
|
|
*
|
|
* Call OS functions without using libc. The example `my_print` could be done in
|
|
* different flavors:
|
|
*
|
|
* **my_print_64:**
|
|
* Using the SYSCALL instruction (successor to SYSENTER). Should work for both
|
|
* IA-64 and AMD64 CPUs, can be ported to `my_print_trap` (see there).
|
|
* Register usage:
|
|
*
|
|
* - RAX: pass syscall number, hold return value from syscall execution
|
|
* - RDI: syscall argument 1
|
|
* - RSI: syscall argument 2
|
|
* - RDX: syscall argument 3
|
|
*
|
|
* **my_print_trap:**
|
|
* Using the trap interrupt to switch to kernel mode. Slower, but
|
|
* architecturally neutral. Register usage:
|
|
*
|
|
* - EAX: pass syscall number, hold return value from syscall execution
|
|
* - EBX: syscall argument 1
|
|
* - ECX: syscall argument 2
|
|
* - EDX: syscall argument 3
|
|
*/
|
|
|
|
#include <asm/unistd.h> /* compile with -m32 for 32-bit syscall numbers,
|
|
without for 64-bit syscall numbers. */
|
|
/* simple inline assembler (asm) requires global symbols */
|
|
#define __NR_exit 60
|
|
// text buffer pointer
|
|
char *my_print_text;
|
|
// text buffer length, print return value
|
|
int my_print_len, my_print_ret;
|
|
// write() syscall number
|
|
int call_write;
|
|
int exitnum;
|
|
|
|
int my_print_64(char *text) {
|
|
my_print_text = text;
|
|
|
|
/* strlen(my_print_text) manually */
|
|
for (my_print_len = 0; my_print_text[my_print_len]; ++my_print_len);
|
|
|
|
/* system call signature:
|
|
* ssize_t write(int fd, const void *buf, size_t count);
|
|
*
|
|
* write() system call number is defined by __NR_write
|
|
*/
|
|
call_write = __NR_write;
|
|
/* stdout is file descriptor no. 1 */
|
|
asm("mov call_write, %rax"); /* arg 0 (rax): syscall number */
|
|
asm("mov $1, %rdi"); /* arg 1 (rdi): file descriptor */
|
|
asm("mov my_print_text, %rsi"); /* arg 2 (rsi): buffer */
|
|
asm("mov my_print_len, %rdx"); /* arg 3 (rdx): length */
|
|
asm("syscall"); /* SYSCALL instruction */
|
|
asm("mov %rax, my_print_ret"); /* save return code (rax) */
|
|
|
|
return my_print_ret;
|
|
}
|
|
|
|
int my_print_trap(char *text) {
|
|
/* system call signature: see my_print_64 */
|
|
|
|
/* TODO */
|
|
|
|
return 7;
|
|
}
|
|
|
|
/* simple inline assembler (asm) requires global symbols */
|
|
|
|
// exit return value
|
|
int my_exit_status;
|
|
|
|
void my_exit_64(int status) {
|
|
my_exit_status = status;
|
|
|
|
/* system call signature:
|
|
* void exit(int status);
|
|
*
|
|
* exit() system call number is defined by __NR_exit
|
|
*/
|
|
|
|
/* TODO */
|
|
// Syscall
|
|
//exitnum = __NR_exit;
|
|
//asm("mov $60, %rax"); // verwende den exitnum / 60 Syscall
|
|
//asm("mov my_exit_status, %rdi"); //status = myexitstatus oder 0
|
|
//asm("syscall");
|
|
//TRAP
|
|
asm("mov $1, %eax");
|
|
asm("mov my_exit_status, %ebx");
|
|
asm("int $0x80");
|
|
|
|
|
|
|
|
}
|
|
|
|
int main(void) {
|
|
my_print_64("Hello World!\n");
|
|
|
|
my_exit_64(42);
|
|
|
|
/* never come here, if my_exit_64 works */
|
|
return 6;
|
|
}
|