System Calls and Inline Assembler
Total Page:16
File Type:pdf, Size:1020Kb
System calls and inline assembler Michal Sojka [email protected] ČVUT, FEL License: CC-BY-SA System calls ● A way for “normal” applications to invoke operating system (OS) kernel's services. ● Applications run in unprivileged CPU mode (user space, user mode) ● OS kernel runs in privileged CPU mode (kernel mode) ● System call is a way how to securely switch from user to kernel mode. What is a system call technically? ● A machine instruction that: – Increases the CPU privilege level and – Passes the control to a predefined place in the kernel. ● Arguments are (typically) passed in CPU registers. ● Instructions: – x86: int 0x80, sysenter, syscall – MIPS: syscall – ARM: swi x86 user execution environment (32 bit) Basic Program Execution Registers Address Space* 2^32 -1 Eight 32-bit General-Purpose Registers Registers General-Purpose Registers 31 16 15 8 07 16-bit 32-bit AH AL AX EAX Six 16-bit Segment Registers Registers BH BL BX EBX General-Purpose Registers 32-bits EFLAGS Register CH CL 031 CX ECX DH DL DX 32-bits EIP (Instruction Pointer Register) EAX EDX BP EBX EBP FPU Registers SI ECX ESI EDX Eight 80-bit Floating-Point DI EDI ESI Registers Data Registers 0 SP EDI ESP *The address space can be flat or segmented. Using EBP 16 bits Control Register the physical address ESP 16 bits Status Register extension mechanism, a physical address space of 16 bits Tag Register 2^36 - 1 canbeaddressed. Segment Registers Opcode Register (11-bits) 15 0 48 bits FPU Instruction Pointer Register CS 48 bits FPU Data (Operand) Pointer Register DS SS MMX Registers ES FS Eight 64-bit Registers MMX Registers GS Program Status and Control Register 31 0 EFLAGS XMM Registers Instruction Pointer 31 0 Eight 128-bit XMM Registers Registers EIP 32-bits MXCSR Register Source: Intel Linux system call ABI (x86, 32-bit) ● Application Binary Interface ● int 0x80 – System call number in EAX ● /usr/include/sys/syscall.h ● /usr/include/asm/unistd_32.h – Arguments ● 1st in EBX, 2nd in ECX, 3rd in EDX, 4th in ESI, 5th in EDI, 6th in EBP – Return value: EAX ● Zero or positive: success ● Negative: error (see /usr/include/asm-generic/errno.h, errno-base) ● sysenter – faster, slightly more complicated Hello world Hello app main() #include <stdio.h> printf() int main (int ar c, char *ar v!") _start # libc $rintf(%&ello world'n(); write() ) Kernel ● Let's look how to do it without libc ● write system call – Documentation: man 2 write – ssize_t write(int fd, const void *buf, size_t count); – Three arguments ● _startup symbol Hello world It's simpler in assembler AT&T assembler syntax: hello0 label: .ascii 1&ello world'n1 instruction src,dst .directive . lobal _start ● _start0 immediate operands preceded by '$' ● register operands preceded by '%' mov 23,4ea5 # write mov 2,,4eb5 # stdout mov 2hello,4ec5 # $tr to data mov 2,2,4ed5 # len th of the data int 26576 ● Compile: gcc -m32 -nostdlib -o hello1 hello1.S ● Run: ./hello1 ● Why it ends with segmentation fault? ● Disassemble the binary: objdump -d hello1 Geting rid of the fault hello0 .ascii 1&ello world'n1 . lobal _start _start0 mov 23,4ea5 # write mov 2,,4eb5 # stdout ● We need to tell the mov 2hello,4ec5 # $tr to data OS that we are about mov 2,2,4ed5 # len th of the data to finish – with exit int 26576 syscall. mov 2,,4ea5 # e5it mov 26,4eb5 # e5it code ● Inspect the syscalls int 26576 invoked by the program: strace ./hello > /dev/null Hello world in C with inline assembler char *hello 8 1&ello world'n1; void _start() Compilation: # gcc -m32 -nostdlib -nostdinc -static -O2 hello2.c -o hello2 asm volatile ( 1mov 23,4ea5;1 1mov 2,,4eb5;1 1mov hello,4ec5;1 1mov 2,2,4ed5;1 1int 265761 ); ) ● But C compiler allows us to do better than that! – Assembler Instructions with C Expression Operands Hello world in C with extended assembler Extended assembler syntax: asm ( assembler tem$late char hello!" 8 1&ello world'n1; 0 out$ut o$erands .* o$tional *. 0 in$ut o$erands .* o$tional *. void _start() 0 list of clobbered re isters .* o$tional *. # ); The syntax after “:” is: int retval; <constraint> (<; e5$ression>), .... asm volatile (1int 265761 0 18a1 (retval) 0 1a1 (3), 1b1 (,), 1c1 (hello), 1d1 (sizeof(hello)*,) 0 %memor:(); asm volatile (1int 265761 0 0 1a1 (,), 1b1 (6)); ) ● Compile: cc *m+2 *nostdlib *nostdinc *static *92 hello+.c *o hello+ ● Disassemble: ob/dum$ *d hello+ C wrappers around system calls static inline lon s:scall,(lon s:scall, lon ar ,) # lon ret; asm volatile (1int 265761 0 18a1 (ret) 0 1a1 (s:scall), 1b1 (ar ,) 0 %memor:(); return ret; ) static inline lon s:scall+(lon s:scall, lon ar ,, lon ar 2, lon ar +) # lon ret; asm volatile (1int 265761 0 18a1 (ret) 0 1a1 (s:scall), 1b1 (ar ,), 1c1 (ar 2), 1d1 (ar +) 0 %memor:(); return ret; ) int write(int fd, const void *buf, int count) # return s:scall+(3, fd, (lon )buf, count); ) void e5it(int status) # s:scall,(,, status); ) void _start() # int retval; retval 8 write(,, 1&ello world'n1, ,2); e5it(6); ) Assignment ● Write a program that: – Opens file “file.txt” (open()) – Reads the first 100 bytes of the file (read()) – Writes the first line (or 100 bytes if the line is linger) of the read data to standard output (write()) – Executes program /bin/date (execve()) ● The program must be compiled without libc i.e. with gcc *nostdlib *nostdinc ... .