Writing assembler
code is very difficult, it's difficult because you have to write
lowest level programming language, you have to write code specific to
architecture of machine, 32bit or 64bit machines.
Take a look at
following assembly code written for x86_64 machine. This code loops
until start reaches to value in max and prints out each value.
.globl _start /* must declare for program to know where to start program,
it's just says which is main function. */
.set start, 0 /*
starting value for the loop index */
.set max, 10 /*
loop exits when the index hits this number (loop condition is i<max)
*/
_start:
mov $start,%r15 /* loop index */
loop:
mov %r15,%r14
/* copy to r14 for ascii conversion */
mov $'0',%r13
/* loding value of start into r13 register */
add %r13,%r14 /* adding r13 and r14 values and result is store into
r14 register */
movq $digit,%rsi
/* message location, rsi is register source index
*/
movb %r14b,(%rsi)
/* write byte to start of message */
movq $len,%rdx
/* message length, rdx is register d extended */
movq $msg,%rsi /* message location, rsi is register source index */
movq $1,%rdi /* file descriptor stdout, rdi is register destination
index */
movq $1,%rax /* syscall, sys_write, rax is register a extended */
syscall
inc %r15
/* increment register 15 */
cmp $max,%r15
/* see if we're done */
jne loop
/* loop if we are not */
mov $0,%rdi /* exit status */
mov $60,%rax
/* syscall sys_exit */
syscall
.data
msg: .ascii
"Loop: #\n"
/* message text - # is number of index */
digit = . - 2 /*
memory address for digit */
len = . - msg /*
length of message */
The code belongs to
Chris Tyler and some of the comments belongs to him as well, it's
quite difficult to understand some of the steps. This code is able to
handle only single digit value for being printed. All the registers
that were used in code above are for only x86_64 machine, for Aarch64
there are different set of registers. Take a look at following table
for some basic difference between x86_64 and Aarch64 machine.
X86_64 | Aarch64 |
---|---|
R8 to r15 are general registers | r0 to r30 are general registers |
rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi are specialied regisers | - |
64-bit registers using the 'r' prefix: rax, r15 32-bit registers using the 'e' prefix (original registers: e_x) or 'd' suffix (added registers: r__d): eax, r15d 16-bit registers using no prefix (original registers: _x) or a 'w' suffix (added registers: r__w): ax, r15w 8-bit registers using 'h' ("high byte" of 16 bits) suffix (original registers - bits 8-15: _h): ah, bh 8-bit registers using 'l' ("low byte" of 16 bits) suffix (original registers - bits 0-7: _l) or 'b' suffix (added registers: r__b): al, bl, r15b |
x0 through x30 - for 64-bit-wide access registers w0 through w30 - for 32-bit-wide access registers |
Openrations like add, divide, multiply takes two parameters and operation result is stored in second parameter. | Openrations like add, divide, multiply takes three parametrs and result is stored in first parameter and other two are for operation values. |
Many differences.. | Many differences.. |
One of the good
thing about writing assembly code is when you compiler it and analyze
executable file using objdump command you will not see any code other
than what you have written but when you write C/C++ code and analyze
it' executable there is a lot of other code that you didn't write,
that code is coming from your includes but since you don't need to
include anything in assembly code so what you write is what you get.
This assembly program is written in .s type extension and you just
run:
ls -o name.o file.s
ld -o executable-name name.o
You can also
write/add assembly code in your C/C++ program using asm function, ex:
asm("add $1, %0"). And to compile this you can just using
gcc or g++ compiler.
No comments:
Post a Comment