Search code examples
assemblyx86nasmmicro-optimization

Conditional function call without using other jumps?


I want to call a procedure depending on the contents of a register. After the procedure has finished it should return to the calling address so that the program can keep executing the code following the call opcode, otherwise it should ignore it and keep executing the rest of the code.

I'm trying to avoid just conditionally jumping over the call with a jcc, like the answers on call subroutines conditionally in assembly describe.

Is it possible? Something like this:

    cmp al,41h      ;check if register has value 41h
    call setAsize   ;call procedure if it does, otherwise ignore and continue executing code
   //more code to execute here


setASize:
    mov al,4d   ;change register content
    ret         ;return to call address so that code following call opcode can continue being executed

How would one implement this without using a jump?


Solution

  • You want to implement a if-else structure in your assembly code as in the following C-code

    if (al == 0x41) { // we keep your example values
        // do something
        setASize();
    } else {
        // do something else
        // not present in your code but there for the sake of completeness
    }
    

    In assembly, you will write this the following way:

        cmp al, h41             ; this is the comparison, which sets flags 
        jne elseBranch          ; if the zero flag is *not* set (al != h41) jump to elseBranch
                            ; the jne instruction can be replaced with any other conditional
                            ; jump to adjust to the test condition
    ifBranch:               ; useless label for clarity
        call setASize           ; this is the actual if-code (do-something)
        jmp endIf               ; now jump to the end of the if to avoid the else-branch
    elseBranch:
                            ; nothing in your code, but this is where you put
                            ; your else instructions
    endIf:
    ; now is the code after your if-else block, which will be executed in any case
    

    This is the one of the two classic ways to write a if-else block in assembly (the reasonning is the same only the instructions change). The other option is to put the else-branch code before the if-branch to have the more logical conditional jump (since in the first example we test equality but jump if not equal). With this second option, the assembly code would be

        cmp al, h41             ; this is the comparison, which sets flags 
        je ifBranch             ; if the zero flag is *not* set (al != h41) jump to elseBranch
                            ; the jne instruction can be replaced with any other conditional
                            ; jump to adjust to the test condition
    elseBranch:             ; useless label for clarity
                            ; nothing in your code, but this is where you put
                            ; your else instructions
        jmp endIf               ; now jump to the end of the if to avoid the else-branch
    ifBranch:
        call setASize           ; this is the actual if-code (do-something)
    endIf:
    ; now is the code after your if-else block, which will be executed in any case
    

    In your case, since there is no else branch, the first option is prefered (only one jump required since you do not need to jump to the elseBranch labels (and do not need the second endIf jump).


    For you code, the final answer would be:

        cmp al,41h
        jne endIf
        call setAsize
    endIf:
                        ; more code here
    
    setASize:
        mov al,4d
        ret