Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segmentation-fault caused by cmp

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.

like image 395
Giganull Avatar asked Feb 03 '18 14:02

Giganull


People also ask

What are the causes of segmentation fault?

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).

How do you fix a segmentation fault?

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.

What causes segmentation fault with pointers?

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.

What causes a segmentation fault 11?

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" .


2 Answers

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
like image 67
ネロク・ゴ Avatar answered Sep 28 '22 08:09

ネロク・ゴ


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
like image 21
Jonathon Reinhart Avatar answered Sep 28 '22 07:09

Jonathon Reinhart