简体   繁体   中英

carry flag in cmp instruction x86

I'm new to x86 and I'm trying to put the larger integer ( at location 4(%esp) and 8(%esp) ) into register %eax. To my understanding, my cmp command will set the carry flag to 1 or zero, then adc will transfer that flag to the eax register. I can then then obtain the value I want by offsetting 4 + flag * 4 from esp. It seems to work in all cases except with negative values and I'm a bit confused?

movl    4(%esp),          %ecx   
cmp     8(%esp),          %ecx   
movl    $0,               %eax   
adc     $0,               %eax   
movl    4(%esp, %esp, 4), %eax   

ps I'm not allowed jumps/braches or fast arithemtic tricks.

The x86, like most two's complement representation CPUs, doesn't actually know if your numbers are signed or not. You simply treat them the way you think they are.

When you do a compare, you are really doing a "subtract" and throwing the answer away. The carry bit is set to the "borrow" from the unsigned subtract of the two numbers. If you are inspecting the carry, after a compare, you are in effect asserting the numbers are unsigned. Thus, you get the wrong answer for signed numbers.

If you want to compare two signed numbers, you need to look at the sign of the difference. There is a problem with the sign if the values are large enough so the difference causes overflows, but we can get around this by using what amounts to a "jump signed less than" (JLT in most x86 assemblers), which takes that into account.

So the simple way to code this following your style:

    movl 4(%esp), %ecx
    cmp 8(%esp), %ecx
    movl $0, %eax
    jlt    L1
    add    $1, %eax
L1: movl 4(%esp, %esp, 4), %eax 

But you said you weren't allowed to use a jmp instruction. Fortunately for you, there is an instruction that does essentially what "jlt .. add $1" pair does called "setge", but it only puts its answer in AL. So we need the movl $0 to zero all of eax before we insert the condition in the bottom byte. (there's one setcc for every jcc in the instruction set). So this would work:

    movl 4(%esp), %ecx
    cmp 8(%esp), %ecx
    movl $0, %eax
    setge   %al      ; use opposite condition than above jle
L1: movl 4(%esp, %esp, 4), %eax 

There's an even handier instruction: mov conditional (cmov), which moves a value to a register if some condition (any expessible jmp condition) is true.

    movl 4($esp), %eax
    movl 8($esp), %ecx
    cmp  %ecx, %eax
    cmovge %ecx, %eax

Homework for the OP: go look up the mov conditional instruction to see why this works.

(I'm not an AT&T assembly language syntax expert; minor errors in the above are possible).

The carry flag contains the result of an unsigned comparison of two values -- an AE (above or equal) comparison in x86 parlance. If you want a signed comparison, you need to use a GE (greater than or equal) comparison, which tests if the sign and overflow flags are equal (carry flag is irrelevant). You can get that into a register with a setge instruction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM