I currently trying to learn assembly language. But I'm stuck. Suppose I have this C code:
for ( int i = 100; i > 0; i-- ) {
// Some code
}
Now I want to do the same in assembly language. I tried it like this:
__asm__ ("movq $100, %rax;"
".loop:"
//Some code
"decq %rax;"
"cmpq $0, (%rax);"
"jnz .loop;"
);
Compile and run results in a seg fault. It does not seg fault if I remove the cmpq line. But then of course the program will not terminate.
So basically my question is what am I doing wrong here?
Thanks in advance.
In practice, segfaults are almost always due to trying to read or write a non-existent array element, not properly defining a pointer before using it, or (in C programs) accidentally using a variable's value as an address (see the scanf example below).
It can be resolved by having a base condition to return from the recursive function. A pointer must point to valid memory before accessing it.
A segmentation fault usually occurs when you try to access data via pointers for which no memory has been allocated. It is thus good practice to initialize pointers with the value NULL, and set it back to NULL after the memory has been released.
However, it usually occurs when you try to do something like access string[4] of a two-char string "nw" or fail to allocate enough memory char string[2] for a string or array like "way" .
The following instruction:
cmpq $0, (%rax)
is accessing the memory address specified by the rax register, whose value is 99.
The first memory page is not mapped. That memory address, 99, belongs to the first memory page. Therefore, the access above results in a segmentation fault.
You don't want the indirection, instead you want:
cmpq $0, %rax
That is, you want to compare against the contents of rax, not the contents at the memory address specified by rax.
Consider however optimizing the cmp instruction away:
decq %rax is immediately preceding the cmp $0, %rax instruction, which sets ZF if rax is zero. The conditional jump is then performed based on the state of the ZF flag:
decq %rax
cmpq $0, %rax
jnz .loop
The dec instruction affects the ZF flag (as cmp does), so if decrementing rax results in zero, ZF will be set. You can take advantage of that fact and place jnz directly after dec. You don't need cmp at all:
decq %rax
jnz .loop
cmpq $0, (%rax)
This instruction will try to read memory at the address in rax.
rax will be 99 the first time. Address 99 is not mapped in, so your program segfaults.
You are intending to compare the value in rax to 0, so remove the parentheses.
cmpq $0, %rax
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With