1

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?

9
  • Possible duplicate of call subroutines conditionally in assembly Commented Apr 2, 2019 at 9:16
  • Can you specify which answer on that page you're referring to? Commented Apr 2, 2019 at 9:57
  • This isn't a duplicate. The answer in that question doesn't execute the call depending on if the condition is met or not. What I have is a sort of if/else problem. If register contains a value, call a procedure, else, ignore and keep executing code. Commented Apr 2, 2019 at 10:09
  • Why are you trying to avoid a jump? That's part of how conditional code is typically done in assembly. There is no single opcode for "call if" in x86 assembly. Alternatively, but probably overkill, if the possible values of al are limited unless you're happy with a table of 256 addresses, you could make a call table where all the values point to a subroutine that does nothing, and the entry at 41h points to setAsize. In this case, a simple compare and jump would be more straightforward. Commented Apr 2, 2019 at 10:42
  • 1
    @user931018 I understand. In this case, it probably is not a terribly fruitful endeavor as far as sharpening your asm skills, other than to learn that sometimes doing a conditional jump is a very concise way to get the job done, and sometimes the only way. In cases where you have multiple tasks based upon multiple small values, you might explore the call table that I mentioned. For example, if you want to call a different subroutine (action) based upon a value of 0, 1, 2, or 3, you can have a table of subroutine labels that you can access rather than using compare and jumps of the value. Commented Apr 2, 2019 at 13:48

2 Answers 2

4

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 
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for this! A very clear but detailed and descriptive answer! As someone who's learning asm this is great!
@user931018: this is a good answer, but it looks like it's answering the question you claimed wasn't a duplicate. But accepting this answer basically shows it is a duplicate. Martin's answer is the one that explains why there's no other reasonable option, and answers the non-duplicate parts of your question.
@PeterCordes I suppose you are correct. However the answers on that question seemed somewhat vague to me and left me wanting more. Simon's answer was a lot easier to understand and the comparison he did using a higher level language also made it easier for someone who's been doing asm for a week to grasp. But I do see the similarities in the answers. To avoid duplicate posts, should I delete this question?
@user931018: No, probably Simon should post it over there, and we should all go upvote it there. :P Don't delete this question, it has 2 good answers so you'd be throwing away valuable content (even if it is maybe harder to find than it needs to be.)
4

I want to call a procedure depending on the contents of a register. ...I'm trying to avoid using a jump here. Is it possible? ... How would one implement this without using a jump?

Unfortunately, most CPUs support conditional execution only for jump/branch instructions.

ARM CPUs support conditional execution for nearly all instructions; the historic 8080 and compatibles (8085, Z80) supported conditional execution of CALL and RET in addition to jumps.

However, x86 CPUs are like most CPUs: Only jump instructions can be executed conditionally.

Hypothetically, you could perhaps use self-modifying code in RAM to perform any instruction conditionally without using jump instructions. However, doing this would only be useful for some feasibility study and not for any real use case.

4 Comments

MIPS also has conditional branch-and-link, but unfortunately not for a condition that you can use directly with slt for a 0 or 1 integer :/ Why are bgezal & bltzal basic instructions and not pseudo-instructions in MIPS?
Self modifying code would also likely need a conditional jump to set the correct code.
Perhaps also worth mentioning that a conditional tail-call is totally fine, and doesn't break return-address prediction or anything. (But you can only do it if the stack is in the same state as on entry to this function, pointing at your own return address which then becomes the next function's return address.)
@lurker What I was talking was the following: Using multiple of cmp, adc and bitwise operations (but no jumps), it should be possible to get a number 1 or 0 based on a condition (e.g. ah=1 if al==0x4E, al=0 otherwise). Now you can use multiple add and and instructions so ah=1 becomes ah=123 (let's say the 2nd byte of the call instruction) and ah=0 becomes ah=0x90 (the nop instruction). Then you always overwrite the 3 (or 5) bytes of the call instruction. As I already said: This has no realistic use case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.