Testing Assembly on 64 bit Architecture Author: mywisdom I prefer to use yasm on 64 bit machines. Installing yasm http://www.tortall.net/projects/yasm/releases/yasm-1.1.0.tar.gz tar zxvf yasm-1.1.0.tar.gz cd yasm-1.1.0 ./configure && make && make install using yasm pretty much the same as nasm: #yasm -f elf -o object.o source.asm * Registers some of 64 bit registers are: - rax (eax in 32 bit) - rbx (ebx) - rcx (ecx) - rdx (edx) - rsp (esp of 64 bit) - rbp (ebp) - rsi (esi) * vsyscall on 64 bit architecture here i see the vsyscall: sh-3.2# cat /usr/include/asm-x86_64/vsyscall.h #ifndef _ASM_X86_64_VSYSCALL_H_ #define _ASM_X86_64_VSYSCALL_H_ enum vsyscall_num { __NR_vgettimeofday, __NR_vtime, __NR_vgetcpu, }; #define VSYSCALL_START (-10UL << 20) #define VSYSCALL_SIZE 1024 #define VSYSCALL_END (-2UL << 20) #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) #endif /* _ASM_X86_64_VSYSCALL_H_ */ --------------------------------------- looking for vyscall_enum we already figure out there are 3 vsyscall: vgettimeofday, vtime,vgetcpu enum vsyscall_num { __NR_vgettimeofday, __NR_vtime, __NR_vgetcpu, }; pretty much the same as 32 bit: ----------------------------- cat /usr/include/asm/vsyscall.h #ifndef _ASM_X86_VSYSCALL_H #define _ASM_X86_VSYSCALL_H enum vsyscall_num { __NR_vgettimeofday, __NR_vtime, __NR_vgetcpu, }; #define VSYSCALL_START (-10UL << 20) #define VSYSCALL_SIZE 1024 #define VSYSCALL_END (-2UL << 20) #define VSYSCALL_MAPPED_PAGES 1 #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) #endif /* _ASM_X86_VSYSCALL_H */ ----------------------- * start Here a simple asm 32 bit hello world: 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!",0xa len equ $ - msg it's normally can be executed on any 32 bit machine. on 64 bit machines resulted a warning: sh-3.2# yasm -f elf hello.asm sh-3.2# ld -o hello hello.o ld: warning: i386 architecture of input file `hello.o' is incompatible with i386:x86-64 output sh-3.2# ./hello Hello, world! sh-3.2# actually i think a simple way about changing the name of register ex: eax becomes rax, so the wrong code that i made: sh-3.2# cat hello.asm section .text global _start _start: mov rdx,len mov rcx,msg mov rbx,1 mov rax,4 int 0x80 mov rbx,0 mov rax,1 int 0x80 section .data msg db "Hello, world!",0xa len equ $ - msg but when i compile it generates fatal error: sh-3.2# yasm -f elf hello.asm hello.asm:4: warning: `rdx' is a register in 64-bit mode hello.asm:4: error: undefined symbol `rdx' (first use) hello.asm:4: error: (Each undefined symbol is reported only once.) hello.asm:5: warning: `rcx' is a register in 64-bit mode hello.asm:5: error: undefined symbol `rcx' (first use) hello.asm:6: warning: `rbx' is a register in 64-bit mode hello.asm:6: error: undefined symbol `rbx' (first use) hello.asm:7: warning: `rax' is a register in 64-bit mode hello.asm:7: error: undefined symbol `rax' (first use) hello.asm:10: warning: `rbx' is a register in 64-bit mode hello.asm:11: warning: `rax' is a register in 64-bit mode To repair that error we need to add a little directive: bits 64 or we can use : USE64, so here our supposely right (actually wrong code for 64 bit machine) : ;this is 32 bit assembly style on 64 register (actually wrong) bits 64 section .text global _start _start: mov rdx,len mov rcx,msg mov rbx,1 mov rax,4 int 0x80 mov rbx,0 mov rax,1 int 0x80 section .data msg db "Hello, world!",0xa len equ $ - msg ----------------------- sh-3.2# yasm -f elf hello.asm sh-3.2# ld -o hello hello.p ld: hello.p: No such file: No such file or directory sh-3.2# ld -o hello hello.o ld: warning: i386 architecture of input file `hello.o' is incompatible with i386:x86-64 output sh-3.2# ./hello Hello, world! sh-3.2# so it can run with that above supposed wrong code (actually above is for 32 bit machines). yep it still 32 bit asm code dude not 64, so now we're gonna convert it into 64 bit assembly codes what's the differences? int 0x80 is for 32 bit machine the equivalent code at 64 bit machine is : syscall User-level applications use as integer registers for passing the sequence: %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi,%rsi, %rdx, %r10, %r8 and %r9. ok here the style of 64 bit asm: 64 bit style -------------- bits 64 section .data msg db "Hello World!",10,0 len equ $ - msg section .text global _start _start: mov rdx, len sub rdx, rcx mov rsi, dword msg push 0x1 pop rax mov rdi,rax syscall xor rdi,rdi push 0x3c pop rax syscall here 32 bit asm style to invoke sys_write mov edx,len mov ecx,msg mov ebx,1 mov eax,4 int 0x80 - mov edx,len -> string length at edx register - mov ecx,msg -> memory address of msg will be at ecx register - mov ebx,0 -> ebx = 0 - mov eax,1 -> we suppy syscall number of sys_write here : 1 - int 0x80 -> finally we call the kernel but the operation is pretty much different in 64 bit machines: mov rdx, len ; we suppy string length at rdx register sub rdx, rcx ; substract rdx with rcx mov rsi, dword msg ; we supply pointer to msg at rsi push 0x1 ; insert 0x1 into stack pop rax ; and then popping it into rax mov rdi,rax syscall