Using the cmp instruction correctly.
Using GNU assembler v. GNU assembler version 2.17.50 (i486-linux-gnu)
Intel machine that's P4 or more.
.section .data
values:
.int 105, 235, 61, 315, 134, 221, 53, 145, 117, 5
.section .text
.globl _start
_start:
nop
movl $values, %esi
movl $9, %ecx
movl $9, %ebx
loop:
cmp (%esi), 4(%esi)
jge skip
xchg %eax, 4(%esi)
movl %eax, (%esi)
skip:
add $4, %esi
dec %ebx
jnz loop
dec %ecx
jz end
movl $values, %esi
movl %ecx, %ebx
jmp loop
end:
movl $1, %eax
movl $0, %ebx
int $0x80
Here's what happens when I assemble it.
exchange02.s:29: Error: too many memory references for `cmp'
This points to the line of code in bold.
If I were to replace that one bold line with these two lines, everything works fine.
movl (%esi), %eax
cmp %eax, 4(%esi)
Here's why I think the above is giving me an assemble time error. Essentially the cmp instruction cannot compare two pieces of memory (sayth so the Intel docs.) Now, when the above instruction (in bold) executes, the parentheses around the two operands force the pointers to which the data is pointing to (and reside in the ESI register) de-reference, thereby creating the above problem that the docs say should not happen.
Is my thinking correct? Yes or no?
# 1 Re: Using the cmp instruction correctly.
Hi,
I'm not sure I understood your reasoning and I don't have a Linux machine to double-check details for opcode suffix ...
The problem with cmp (%esi), 4(%esi) is that to the processor it is not clear how much memory it must compare: bytes, words, double words ? For that reason it is incorrect to have both operators pointing to memory.
Therefore you should use opcode CMPSB/CMPSW/CMPSD for comparison at a byte/word/double-word level. This opcode needs no operands but before its execution you need to define %edi and %esi pointing to memory locations you want to compare. After each execution of CMPSx, both %esi and %edi will be incremented or decremented depending on current Direction Flag.
In contrast, note that assembler wouldn't complain with the following line:
cmp %ah,4(%esi)
Since size of %ah is 1 byte, it is now clear that only one byte is compared at a time.
Best regards,
Iaki Viggers
# 3 Re: Using the cmp instruction correctly.
It's not the size of operand that the compiler complains, it's just that YOU CANNOT HAVE 2 MEMORY POINTERS in a single instruction. You are trying to compare the values of 2 locations in which the processor cant do. You can only compare memory values with a register or an immediate value.
When you want to compare the values located at [esi] and [esi + 4], you have to copy first the other value into a register, say eax, and than compare eax with the other value.
It's also the same with MOV instructions, you have to pass the value to a register first and then place the register value in the memory destination (except in cases movsb, movsw, etc.)
Hope it will help you. :) :) :)
# 4 Re: Using the cmp instruction correctly.
Nobody in this thread said that compiler/assembler complains about size of operands. It only complains about having two operands pointing to memory. This thread is actually about what causes the error at assemble time.
The reason of why there can't be two memory pointers in an opcode (unspecified size of memory targeted) and workaround for that is explained above.