Assembler unter Linux
Einleitung
Auf dieser Seite geht es um Assemblerprogrammieung unter Linux, vor allemin Bezug auf Syscalls unter Linux auf einer x86_64 CPU. Ich gehe davon aus, dass Grundlegendes wissen über die Programmierung in C und Assembler vorhanden ist. Ich arbeite mit dem Netwide Assembler (NASM).
Für Kommentare oder Fragen, nutzt bitte das Gästebuch.
Einfaches "Hello World"-Programm
Der folgende Code ist von hier geklaut:
section .text
global _start
_start:
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80
mov ebx,0
mov eax,1
int 0x80
section .data
msg db 'Hello world',0x0A
len equ $ - msg
Assemblieren kann man das ganze mit einem
nasm -f elf -g <name>.asm && ld -o <name> <name>.o
Leute, die wie ich ein 64-Bit System haben sollten das so machen:
nasm -f elf64 -g <name>.asm && ld -o <name> <name>.o
Ausführen wie gewohnt mit
./<name>
Was passiert? int 0x80 ist der Software-Interrupt von Linux, der für Syscalls zuständig ist. Jeder Syscall hat eine ihm zugeordnete Nummer:
0 sys_setup
1 sys_exit
2 sys_fork
3 sys_read
4 sys_write
5 sys_open
6 sys_close
uvm.
Diese Nummer wird im Register EAX abgelegt, die Parameter für den Syscall kommen in die Register
EBX
ECX
EDX
ESI
EDI
EBP.
SYS_WRITE erwartet zum Beispiel drei Parameter:
Einen Filepointer, den Pointer auf Daten und eine Länge.
Als Datei nehmen wir STDOUT (1), speichern also 1 im Register EBX. Für die Daten nehmen wir den Pointer auf unsere Zeichenkette und speichern ihn in ECX und die Länge kommt in EDX.
Am Ende rufen wir SYS_EXIT(0) auf, was einem return 0 in C entspricht.
Umfangreicheres Programm
Das bekannte 99 Bottles Of Beer:
section .text
global _start
_start:
call printbttls
mov edx,wall_l
mov ecx,wall
mov ebx,1
mov eax,4
int 0x80 ; sys_write
call printbttls
mov edx,beer_l
mov ecx,beer
mov ebx,1
mov eax,4
int 0x80 ; sys_write
mov al,[nr]
mov ah,[nr+1]
dec ah
cmp ah,0x2F
jne nureinestelle
mov ah,0x39
dec al
nureinestelle:
cmp ax,0x392F
je ende
mov [nr],al
mov [nr+1],ah
mov edx,take_l
mov ecx,take
mov ebx,1
mov eax,4
int 0x80 ; sys_write
call printbttls
mov edx,wall_l
mov ecx,wall
mov ebx,1
mov eax,4
int 0x80 ; sys_write
mov edx,1
mov ecx,nl
mov ebx,1
mov eax,4
int 0x80 ; sys_write
jmp _start
ende:
mov edx,store_l
mov ecx,store
mov ebx,1
mov eax,4
int 0x80 ; sys_write
mov ax,0x3939
mov [nr],al
mov [nr+1],ah
call printbttls
mov edx,wall_l
mov ecx,wall
mov ebx,1
mov eax,4
int 0x80 ; sys_write
mov ebx,0
mov eax,1
int 0x80 ; sys_exit(0)
printbttls:
mov al,[nr]
mov ah,[nr+1]
cmp al,0x30
je erstenull
mov edx,2
mov ecx,nr
mov ebx,1
mov eax,4
int 0x80 ; sys_write
jmp rest
erstenull:
cmp ah,0x30
je zweitenull
mov edx,1
mov ecx,nr+1
mov ebx,1
mov eax,4
int 0x80 ; sys_write
jmp rest
zweitenull:
mov edx,no_l
mov ecx,no
mov ebx,1
mov eax,4
int 0x80 ; sys_write
rest:
mov al,[nr]
mov ah,[nr+1]
cmp ax,0x3130
je singular
mov edx,bttl_l
mov ecx,bttl
mov ebx,1
mov eax,4
int 0x80 ; sys_write
ret
singular:
mov edx,bttls_l
mov ecx,bttls
mov ebx,1
mov eax,4
int 0x80 ; sys_write
ret
section .data
nr db '99'
bttl db ' bottles '
bttl_l equ $ - bttl
bttls db ' bottle '
bttls_l equ $ - bttls
wall db 'of beer on the wall',0x0A
wall_l equ $ - wall
beer db 'of beer',0x0A
beer_l equ $ - beer
no db 'No more'
no_l equ $ - no
take db 'Take one down, pass it around',0x0A
take_l equ $ - take
store db 'Go to the store, buy some more',0x0A
store_l equ $ - store
nl equ store + store_l - 1
INT 0x80 und Syscalls
Das obige Programm hat einen kleinen Nachteil. Auf neueren Prozessoren ist der Software-Interrupt ziemlich langsam. Zum Glück stehen schnellere Befehle zu Verfügung wie SYSENTER und SYSCALL (nur auf sehr neuen Prozessoren). Linux hat einen tollen Mechanismus namens vsyscall, der sich automatisch darum kümmert, dass SYSENTER aufgerufen wird falls möglich und INT 0x80 ansonsten.
Leider scheint vsyscall nur unter 32-Bit System gut zu funktionieren. (Ich hoffe ich schreibe hier nix falsches, aber ich habe nix dazu gefunden, bzw, was ich gefunden habe hat nicht funktioniert... Bitte um Rückmeldung, falls ihr mehr wisst.) Aber auf allen x86_64 CPUs gibt es den SYSCALL Befehl, daher kann man ihn immer Benutzen, wenn man 64-Bit Software schreib.
Das nächste Problem ist, dass die Argumente bei SYSCALL in andere Register gehören, als bei INT 0x80, die Syscallnummer wird weiterhin im Register EAX (bzw. RAX) abgelegt, die Parameter für den Syscall kommen aber in die Register
RDI
RSI
RDX
RCX
R8
R9.
Aber auch die Syscallnummern sind andere. Deswegen habe ich folgende beiden Includedateien geschrieben, die auch als Übersicht nützlich sind:
Syscallnummern INT 0x80
; FILE syscall_32_int80.inc
%define _syscall int 0x80
%define _nr eax
%define _arg1 ebx
%define _arg2 ecx
%define _arg3 edx
%define _arg4 esi
%define _arg5 edi
%define _arg6 ebp
%define _sys_setup 0
%define _sys_exit 1
%define _sys_fork 2
%define _sys_read 3
%define _sys_write 4
%define _sys_open 5
%define _sys_close 6
%define _sys_waitpid 7
%define _sys_creat 8
%define _sysink 9
%define _sys_unlink 10
%define _sys_execve 11
%define _sys_chdir 12
%define _sys_time 13
%define _sys_mknod 14
%define _sys_chmod 15
%define _syschown 16
%define _sys_break 17
%define _sys_oldstat 18
%define _sysseek 19
%define _sys_getpid 20
%define _sys_mount 21
%define _sys_umount 22
%define _sys_setuid 23
%define _sys_getuid 24
%define _sys_stime 25
%define _sys_ptrace 26
%define _sys_alarm 27
%define _sys_oldfstat 28
%define _sys_pause 29
%define _sys_utime 30
%define _sys_stty 31
%define _sys_gtty 32
%define _sys_access 33
%define _sys_nice 34
%define _sys_ftime 35
%define _sys_sync 36
%define _sys_kill 37
%define _sys_rename 38
%define _sys_mkdir 39
%define _sys_rmdir 40
%define _sys_dup 41
%define _sys_pipe 42
%define _sys_times 43
%define _sys_prof 44
%define _sys_brk 45
%define _sys_setgid 46
%define _sys_getgid 47
%define _sys_signal 48
%define _sys_geteuid 49
%define _sys_getegid 50
%define _sys_acct 51
%define _sys_umount2 52
%define _sysock 53
%define _sys_ioctl 54
%define _sys_fcntl 55
%define _sys_mpx 56
%define _sys_setpgid 57
%define _sys_ulimit 58
%define _sys_oldolduname 59
%define _sys_umask 60
%define _sys_chroot 61
%define _sys_ustat 62
%define _sys_dup2 63
%define _sys_getppid 64
%define _sys_getpgrp 65
%define _sys_setsid 66
%define _sys_sigaction 67
%define _sys_sgetmask 68
%define _sys_ssetmask 69
%define _sys_setreuid 70
%define _sys_setregid 71
%define _sys_sigsuspend 72
%define _sys_sigpending 73
%define _sys_sethostname 74
%define _sys_setrlimit 75
%define _sys_getrlimit 76
%define _sys_getrusage 77
%define _sys_gettimeofday 78
%define _sys_settimeofday 79
%define _sys_getgroups 80
%define _sys_setgroups 81
%define _sys_select 82
%define _sys_symlink 83
%define _sys_oldlstat 84
%define _sys_readlink 85
%define _sys_uselib 86
%define _sys_swapon 87
%define _sys_reboot 88
%define _sys_readdir 89
%define _sys_mmap 90
%define _sys_munmap 91
%define _sys_truncate 92
%define _sys_ftruncate 93
%define _sys_fchmod 94
%define _sys_fchown 95
%define _sys_getpriority 96
%define _sys_setpriority 97
%define _sys_profil 98
%define _sys_statfs 99
%define _sys_fstatfs 100
%define _sys_ioperm 101
%define _sys_socketcall 102
%define _sys_syslog 103
%define _sys_setitimer 104
%define _sys_getitimer 105
%define _sys_stat 106
%define _sysstat 107
%define _sys_fstat 108
%define _sys_olduname 109
%define _sys_iopl 110
%define _sys_vhangup 111
%define _sys_idle 112
%define _sys_vm86old 113
%define _sys_wait4 114
%define _sys_swapoff 115
%define _sys_sysinfo 116
%define _sys_ipc 117
%define _sys_fsync 118
%define _sys_sigreturn 119
%define _sys_clone 120
%define _sys_setdomainname 121
%define _sys_uname 122
%define _sys_modifydt 123
%define _sys_adjtimex 124
%define _sys_mprotect 125
%define _sys_sigprocmask 126
%define _sys_create_module 127
%define _sys_init_module 128
%define _sys_delete_module 129
%define _sys_get_kernel_syms 130
%define _sys_quotactl 131
%define _sys_getpgid 132
%define _sys_fchdir 133
%define _sys_bdflush 134
%define _sys_sysfs 135
%define _sys_personality 136
%define _sys_afs_syscall 137
%define _sys_setfsuid 138
%define _sys_setfsgid 139
%define _sys_lseek 140
%define _sys_getdents 141
%define _sys__newselect 142
%define _sys_flock 143
%define _sys_msync 144
%define _sys_readv 145
%define _sys_writev 146
%define _sys_getsid 147
%define _sys_fdatasync 148
%define _sys__sysctl 149
%define _sys_mlock 150
%define _sys_munlock 151
%define _sys_mlockall 152
%define _sys_munlockall 153
%define _sys_sched_setparam 154
%define _sys_sched_getparam 155
%define _sys_sched_setscheduler 156
%define _sys_sched_getscheduler 157
%define _sys_sched_yield 158
%define _sys_sched_get_priority_max 159
%define _sys_sched_get_priority_min 160
%define _sys_sched_rr_get_interval 161
%define _sys_nanosleep 162
%define _sys_mremap 163
%define _sys_setresuid 164
%define _sys_getresuid 165
%define _sys_vm86 166
%define _sys_query_module 167
%define _sys_poll 168
%define _sys_nfsservctl 169
%define _sys_setresgid 170
%define _sys_getresgid 171
%define _sys_prctl 172
%define _sys_rt_sigreturn 173
%define _sys_rt_sigaction 174
%define _sys_rt_sigprocmask 175
%define _sys_rt_sigpending 176
%define _sys_rt_sigtimedwait 177
%define _sys_rt_sigqueueinfo 178
%define _sys_rt_sigsuspend 179
%define _sys_pread 180
%define _sys_pwrite 181
%define _sys_chown 182
%define _sys_getcwd 183
%define _sys_capget 184
%define _sys_capset 185
%define _sys_sigaltstack 186
%define _sys_sendfile 187
%define _sys_getpmsg 188
%define _sys_putpmsg 189
%define _sys_vfork 190
Syscallnummern SYSCALL
; FILE syscall_64_syscall.inc
%define _syscall syscall
%define _nr rax
%define _arg1 rdi
%define _arg2 rsi
%define _arg3 rdx
%define _arg4 rcx
%define _arg5 r8
%define _arg6 r9
%define _sys_read 0
%define _sys_write 1
%define _sys_open 2
%define _sys_close 3
%define _sys_stat 4
%define _sys_fstat 5
%define _sysstat 6
%define _sys_poll 7
%define _sysseek 8
%define _sys_mmap 9
%define _sys_mprotect 10
%define _sys_munmap 11
%define _sys_brk 12
%define _sys_rt_sigaction 13
%define _sys_rt_sigprocmask 14
%define _sys_rt_sigreturn 15
%define _sys_ioctl 16
%define _sys_pread64 17
%define _sys_pwrite64 18
%define _sys_readv 19
%define _sys_writev 20
%define _sys_access 21
%define _sys_pipe 22
%define _sys_select 23
%define _sys_sched_yield 24
%define _sys_mremap 25
%define _sys_msync 26
%define _sys_mincore 27
%define _sys_madvise 28
%define _sys_shmget 29
%define _sys_shmat 30
%define _sys_shmctl 31
%define _sys_dup 32
%define _sys_dup2 33
%define _sys_pause 34
%define _sys_nanosleep 35
%define _sys_getitimer 36
%define _sys_alarm 37
%define _sys_setitimer 38
%define _sys_getpid 39
%define _sys_sendfile 40
%define _sys_socket 41
%define _sys_connect 42
%define _sys_accept 43
%define _sys_sendto 44
%define _sys_recvfrom 45
%define _sys_sendmsg 46
%define _sys_recvmsg 47
%define _sys_shutdown 48
%define _sys_bind 49
%define _sysisten 50
%define _sys_getsockname 51
%define _sys_getpeername 52
%define _sys_socketpair 53
%define _sys_setsockopt 54
%define _sys_getsockopt 55
%define _sys_clone 56
%define _sys_fork 57
%define _sys_vfork 58
%define _sys_execve 59
%define _sys_exit 60
%define _sys_wait4 61
%define _sys_kill 62
%define _sys_uname 63
%define _sys_semget 64
%define _sys_semop 65
%define _sys_semctl 66
%define _sys_shmdt 67
%define _sys_msgget 68
%define _sys_msgsnd 69
%define _sys_msgrcv 70
%define _sys_msgctl 71
%define _sys_fcntl 72
%define _sys_flock 73
%define _sys_fsync 74
%define _sys_fdatasync 75
%define _sys_truncate 76
%define _sys_ftruncate 77
%define _sys_getdents 78
%define _sys_getcwd 79
%define _sys_chdir 80
%define _sys_fchdir 81
%define _sys_rename 82
%define _sys_mkdir 83
%define _sys_rmdir 84
%define _sys_creat 85
%define _sysink 86
%define _sys_unlink 87
%define _sys_symlink 88
%define _sys_readlink 89
%define _sys_chmod 90
%define _sys_fchmod 91
%define _sys_chown 92
%define _sys_fchown 93
%define _syschown 94
%define _sys_umask 95
%define _sys_gettimeofday 96
%define _sys_getrlimit 97
%define _sys_getrusage 98
%define _sys_sysinfo 99
%define _sys_times 100
%define _sys_ptrace 101
%define _sys_getuid 102
%define _sys_syslog 103
%define _sys_getgid 104
%define _sys_setuid 105
%define _sys_setgid 106
%define _sys_geteuid 107
%define _sys_getegid 108
%define _sys_setpgid 109
%define _sys_getppid 110
%define _sys_getpgrp 111
%define _sys_setsid 112
%define _sys_setreuid 113
%define _sys_setregid 114
%define _sys_getgroups 115
%define _sys_setgroups 116
%define _sys_setresuid 117
%define _sys_getresuid 118
%define _sys_setresgid 119
%define _sys_getresgid 120
%define _sys_getpgid 121
%define _sys_setfsuid 122
%define _sys_setfsgid 123
%define _sys_getsid 124
%define _sys_capget 125
%define _sys_capset 126
%define _sys_rt_sigpending 127
%define _sys_rt_sigtimedwait 128
%define _sys_rt_sigqueueinfo 129
%define _sys_rt_sigsuspend 130
%define _sys_sigaltstack 131
%define _sys_utime 132
%define _sys_mknod 133
%define _sys_uselib 134
%define _sys_personality 135
%define _sys_ustat 136
%define _sys_statfs 137
%define _sys_fstatfs 138
%define _sys_sysfs 139
%define _sys_getpriority 140
%define _sys_setpriority 141
%define _sys_sched_setparam 142
%define _sys_sched_getparam 143
%define _sys_sched_setscheduler 144
%define _sys_sched_getscheduler 145
%define _sys_sched_get_priority_max 146
%define _sys_sched_get_priority_min 147
%define _sys_sched_rr_get_interval 148
%define _sys_mlock 149
%define _sys_munlock 150
%define _sys_mlockall 151
%define _sys_munlockall 152
%define _sys_vhangup 153
%define _sys_modifydt 154
%define _sys_pivot_root 155
%define _sys__sysctl 156
%define _sys_prctl 157
%define _sys_arch_prctl 158
%define _sys_adjtimex 159
%define _sys_setrlimit 160
%define _sys_chroot 161
%define _sys_sync 162
%define _sys_acct 163
%define _sys_settimeofday 164
%define _sys_mount 165
%define _sys_umount2 166
%define _sys_swapon 167
%define _sys_swapoff 168
%define _sys_reboot 169
%define _sys_sethostname 170
%define _sys_setdomainname 171
%define _sys_iopl 172
%define _sys_ioperm 173
%define _sys_create_module 174
%define _sys_init_module 175
%define _sys_delete_module 176
%define _sys_get_kernel_syms 177
%define _sys_query_module 178
%define _sys_quotactl 179
%define _sys_nfsservctl 180
%define _sys_getpmsg 181
%define _sys_putpmsg 182
%define _sys_afs_syscall 183
%define _sys_tuxcall 184
%define _sys_security 185
%define _sys_gettid 186
%define _sys_readahead 187
%define _sys_setxattr 188
%define _syssetxattr 189
%define _sys_fsetxattr 190
%define _sys_getxattr 191
%define _sysgetxattr 192
%define _sys_fgetxattr 193
%define _sysistxattr 194
%define _syslistxattr 195
%define _sys_flistxattr 196
%define _sys_removexattr 197
%define _sysremovexattr 198
%define _sys_fremovexattr 199
%define _sys_tkill 200
%define _sys_time 201
%define _sys_futex 202
%define _sys_sched_setaffinity 203
%define _sys_sched_getaffinity 204
%define _sys_set_thread_area 205
%define _sys_io_setup 206
%define _sys_io_destroy 207
%define _sys_io_getevents 208
%define _sys_io_submit 209
%define _sys_io_cancel 210
%define _sys_get_thread_area 211
%define _sysookup_dcookie 212
%define _sys_epoll_create 213
Programm mit Include
Das 99 Bottles Of Beer sieht jetzt so aus:
section .text
global _start
_start:
;%include "syscall_32_int80.inc"
%include "syscall_64_syscall.inc"
call printbttls
mov _arg3,wall_l
mov _arg2,wall
mov _arg1,1
mov _nr,_sys_write
_syscall
call printbttls
mov _arg3,beer_l
mov _arg2,beer
mov _arg1,1
mov _nr,_sys_write
_syscall
mov al,[nr]
mov ah,[nr+1]
dec ah
cmp ah,0x2F
jne nureinestelle
mov ah,0x39
dec al
nureinestelle:
cmp ax,0x392F
je ende
mov [nr],al
mov [nr+1],ah
mov _arg3,take_l
mov _arg2,take
mov _arg1,1
mov _nr,_sys_write
_syscall
call printbttls
mov _arg3,wall_l
mov _arg2,wall
mov _arg1,1
mov _nr,_sys_write
_syscall
mov _arg3,1
mov _arg2,nl
mov _arg1,1
mov _nr,_sys_write
_syscall
jmp _start
ende:
mov _arg3,store_l
mov _arg2,store
mov _arg1,1
mov _nr,_sys_write
_syscall
mov ax,0x3939
mov [nr],al
mov [nr+1],ah
call printbttls
mov _arg3,wall_l
mov _arg2,wall
mov _arg1,1
mov _nr,_sys_write
_syscall
mov _arg1,0
mov _nr,_sys_exit
_syscall
printbttls:
mov al,[nr]
mov ah,[nr+1]
cmp al,0x30
je erstenull
mov _arg3,2
mov _arg2,nr
mov _arg1,1
mov _nr,_sys_write
_syscall
jmp rest
erstenull:
cmp ah,0x30
je zweitenull
mov _arg3,1
mov _arg2,nr+1
mov _arg1,1
mov _nr,_sys_write
_syscall
jmp rest
zweitenull:
mov _arg3,no_l
mov _arg2,no
mov _arg1,1
mov _nr,_sys_write
_syscall
rest:
mov al,[nr]
mov ah,[nr+1]
cmp ax,0x3130
je singular
mov _arg3,bttl_l
mov _arg2,bttl
mov _arg1,1
mov _nr,_sys_write
_syscall
ret
singular:
mov _arg3,bttls_l
mov _arg2,bttls
mov _arg1,1
mov _nr,_sys_write
_syscall
ret
section .data
nr db '99'
bttl db ' bottles '
bttl_l equ $ - bttl
bttls db ' bottle '
bttls_l equ $ - bttls
wall db 'of beer on the wall',0x0A
wall_l equ $ - wall
beer db 'of beer',0x0A
beer_l equ $ - beer
no db 'No more'
no_l equ $ - no
take db 'Take one down, pass it around',0x0A
take_l equ $ - take
store db 'Go to the store, buy some more',0x0A
store_l equ $ - store
nl equ store + store_l - 1