There's a few things to note about 64 bit as the assembly has changed quite a bit. A good resource that outlines some of these differences is http://www.milw0rm.com/papers/110.
Let's take one of my very first ASM application (32 bit ) :
The equivalent C code for the above is:
.data
string: .asciz "Looping!\n"
len = . - string - 1
.text
.global _start
_start:
movl $0,%ecx # set the inital counter value
compare:
cmpl $9,%ecx # compare to what is in %ecx
jle write # call if less than or equal
jmp exit # otherwise, exit
write:
pushl $len # pushl length of string
pushl $string # pushl the string
pushl $1 # pushl the file descriptor
movl $4,%eax # move the value '4' into %eax: write()
call kernel # call kernel, execute syscall
addl $12,%esp # clean stack
jmp increment # jump to the increment procedure
increment:
incl %ecx # increment the value in %ecx by 1
jmp compare # jump back to the compare procedure
exit:
pushl $0 # pushl our exit status
movl $1,%eax # move the value '1' into %eax: exit()
call kernel # call kernel, execute syscall
kernel: # call the kernel
int $0x80
ret
int main () {
int i;
for ( i=0;i<9;i++)
{
puts ("Looping\n");
}
}
Here is the break down:
There are 6 main 'functions' - start, compare, write, increment, exit and kernel
start: this is equivalent to 'main' in c based languages
compare: compare the current counter value with '9' ( which will exit the 'loop' )
write: write the string 'Looping\n'
increment: increment the counter by 1
exit: exit the application
kernel: call the kernel - called in 'write' and 'exit'
The flow of the application is:
- set the counter
- test if the value of the counter is <= 9
- if the counter is <= 9 call the write function
- the write function will write 'Looping\n' then call increment
- increment will incremenent the counter by '1' and call the compare function
- once the counter is equal to 9 the exit function is called and the application exits
In this loop application, the following syscalls are used ( see /usr/src/sys/sys/syscall.h ) :
syscall 1 - exit : void exit(int status);
syscall 4 - write : write(int d, const void *buf, size_t nbytes);
Note: check the man pages for relevant args.
When this is compiled on a 64 bit machine, 'as' produces the following error:
$ as loop.s -o loop.oAfter a bit of research, i've rewritten the application. The following differences should be noted:
loop.s: Assembler messages:
loop.s:18: Error: suffix or operands invalid for `push'
loop.s:19: Error: suffix or operands invalid for `push'
loop.s:20: Error: suffix or operands invalid for `push'
loop.s:31: Error: suffix or operands invalid for `push'
- Instead of calling the kernel with int 80, i've used 'syscall'
- pushq and movq have replaced pushl and mov
- rdx, rdi, rsi have been used to store arguments instead of pushing them on the stack
- rax has replaced eax
The 64 bit is as follows :
.data
string: .asciz "Looping!\n"
len = . - string - 1
.text
.global _start
_start:
movq $0,%r12 # set the inital counter value
compare:
cmp $9,%r12 # compare to counter value ( 9 iterations )
jle write # call if less than or equal
jmp exit # otherwise, exit
write:
xor %rdx,%rdx
movq $len,%rdx # length of string
movq $string,%rsi # the string
movq $1,%rdi # the file descriptor
movq $4,%rax # move the value '4' into %eax: write()
syscall
jmp increment # jump to the increment procedure
increment:
inc %r12 # increment the counter by 1
jmp compare # jump back to the compare procedure
exit:
movq $1,%rax # syscall 1 ( exit )
syscall
You can compile the above code with the following commands:
$ as loop.s -o loop.o
$ ld -s loop.o -o loop
To show that it is indeed a 64 bit application:
$ file loop
loop: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), statically linked, stripped
No comments:
Post a Comment