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