SpilledMango
SpilledMango

Reputation: 615

Assembly jumps automatically to next label

I've written a program in assembly that look like this:

%macro print 1

    push rbp

    mov rdi, %1
    xor rax, rax

    call _printf

    pop rbp

%endmacro    
section .data
    e db 'Equal', 0
    l db 'Less than', 0
    g db 'Greater than', 0
section .text
        global start
        extern _printf
    start:
        mov rax, 5
        mov rbx, 5
        cmp rax, rbx ; Compare 4 and 5
        je _equal ; je = jump if equal
        cmp rax, rbx
        jl _less ; jl = jump if less
        cmp rax, rbx
        jg _greater ; jg = jump if greater

        ret

_equal:
    print e
_less:
    print l
_greater:
    print g

But when I run the program it jumps to _equal, but it then jumps to _less, and _greater. How can I disable this auto-jumping?

Upvotes: 1

Views: 2515

Answers (2)

Cody Gray
Cody Gray

Reputation: 244722

mov rax, 5

This is an inefficient way to write mov eax, 5. If you're only moving a 32-bit value into a 64-bit register, then you don't need to specify the 64-bit register as an operand. Just specify the 32-bit register, and the upper 32 bits will be implicitly zeroed.

Same thing for:

xor rax, rax

You can just write xor eax, eax, and let the upper 32 bits be implicitly zeroed.

cmp rax, rbx ; Compare 4 and 5

Since you know that you are only comparing 32-bit values, you can write cmp eax, ebx to compare only the lower 32-bit halves. This is smaller and more efficient. You only need cmp rax, rbx if you actually want to compare the entire 64-bit values in those registers.

Of course, the whole code is a little bit silly, as you already know how 4 compares to 5—this doesn't need to be executed at runtime.

But let's assume that these were run-time values, and you did need to do the comparison. You still only need to do the comparison once. So this code:

cmp rax, rbx ; Compare 4 and 5
je _equal ; je = jump if equal
cmp rax, rbx
jl _less ; jl = jump if less
cmp rax, rbx
jg _greater ; jg = jump if greater

can be simplified to:

cmp rax, rbx
je  _equal
jl  _less
jg  _greater

since conditional-jump instructions do not alter flags.

But when I run the program it jumps to _equal, but it then jumps to _less, and _greater. How can I disable this auto-jumping?

As has already been pointed out in the comments and another answer, it is not actually jumping, since it's not skipping any instructions. It's just falling through to the next label.

One way to prevent this—as user3344003 advised—is to add an unconditional jump instruction after each case. Something like:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater
finished:
    ret

_equal:
    print e
    jmp   finished
_less:
    print l
    jmp   finished
_greater:
    print g
    jmp   finished

Actually, though, all you're doing is jumping back to return. A single ret instruction is smaller in size than a jmp instruction, and also more efficient since no branch needs to be taken. You would only use this pattern if you had a bunch of clean-up code that needed to run before returning. In this simple case, you can do:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater

_equal:
    print e
    ret
_less:
    print l
    ret
_greater:
    print g
    ret

Notice that I've omitted the ret after the jg instruction. You don't need it—equal, less, and greater exhaustively cover every possibility, so one of the three branches is guaranteed to be taken. In fact, that means you can rearrange the code to eliminate one of the branches, taking advantage of the very fall-through that was originally confusing you:

    cmp rax, rbx
    jl  _less
    jg  _greater

    ; fall through to 'equal' case
    print e
    ret

_less:
    print l
    ret

_greater:
    print g
    ret

Fun fact: this is essentially identical to the code that GCC would generate if you'd written this in C.

Upvotes: 5

user3344003
user3344003

Reputation: 21607

You need to put a jump instruction after each case (print macro expansion). It's just falling through, not jumping.

Upvotes: 1

Related Questions