flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Main > General Assembly Control Flow Tips

Author
Thread Post new topic Reply to topic
moveax41h



Joined: 18 Feb 2018
Posts: 20

General Assembly Control Flow Tips

Hello,

So I am pretty familiar with basic usage of x86 assembly instruction set at this point as well as the main CPU flags.

However, when I write asm programs, I am finding that I am struggling with program control flow because of the linear nature of assembly. What I mean by this is, I can use cmp and conditional jmp instructions, but I am not accounting for the fact that, for example, if the jump is not taken, the control flow falls through to areas that I don't want it to.

Obviously, in C and higher, if statements make this crystal clear... But in assembly, I am finding that my programs step into areas that I do not want. For example, I wrote a program which does a pushf, loads the flags into ax, and then does some bit masks to check each individual flag and it's supposed to output whether each flag is set via printf msvcrt. Here is a small snippet:

Code:

check_parity_flag:
        mov eaxesi
        mov axdx
        and ax4h
        cmp ax4h
        je parity_flag_set
check_aux_flag:
        mov eaxesi
        mov axdx
        and ax10h
        cmp ax10h
        je aux_flag_set




The thing is, if for example the parity flag is not set, execution falls through to check_aux_flag but my mov, eax esi instruction is only valid if the code at parity_flag_set is executed BEFORE the code at check_aux_flag. If the parity flag is NOT set, the execution falls through to mov eax, esi and it overwites eax with the value in esi that I do not want and messes up the rest of the program.

Are there any good books or resources on how to properly structure your assembly program to avoid these kinds of pitfalls? I obviously understand that this is a problem, but since I am still new to this, I am having a hard time coming up with a solution in an elegant way without making the program unnecessarily complex and confusing. In this example, I have code at parity_flag_set and aux_flag_set which calls printf and thus clears out the registers that I want. Is this just because I need to be using memory and cannot effectively accomplish this with registers only?

Thank you.

_________________
-moveax41h
Post 02 Mar 2018, 11:39
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15725
Location: Yonada


Code:
  cmp one_thing,another_thing
  jz .test1_equal
  ;test1 not equal path
  ;...
  jmp .test1_done
.test1_equal:
  ;test1 equal path
  ;...
.test1_done:

Post 02 Mar 2018, 11:46
View user's profile Send private message Visit poster's website Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 231
Location: Belarus

Re: General Assembly Control Flow Tips


moveax41h wrote:
Hello,

So I am pretty familiar with basic usage of x86 assembly instruction set at this point as well as the main CPU flags.

However, when I write asm programs, I am finding that I am struggling with program control flow because of the linear nature of assembly. What I mean by this is, I can use cmp and conditional jmp instructions, but I am not accounting for the fact that, for example, if the jump is not taken, the control flow falls through to areas that I don't want it to.

Obviously, in C and higher, if statements make this crystal clear... But in assembly, I am finding that my programs step into areas that I do not want. For example, I wrote a program which does a pushf, loads the flags into ax, and then does some bit masks to check each individual flag and it's supposed to output whether each flag is set via printf msvcrt. Here is a small snippet:

Code:

check_parity_flag:
        mov eaxesi
        mov axdx
        and ax4h
        cmp ax4h
        je parity_flag_set
check_aux_flag:
        mov eaxesi
        mov axdx
        and ax10h
        cmp ax10h
        je aux_flag_set




The thing is, if for example the parity flag is not set, execution falls through to check_aux_flag but my mov, eax esi instruction is only valid if the code at parity_flag_set is executed BEFORE the code at check_aux_flag. If the parity flag is NOT set, the execution falls through to mov eax, esi and it overwites eax with the value in esi that I do not want and messes up the rest of the program.

Are there any good books or resources on how to properly structure your assembly program to avoid these kinds of pitfalls? I obviously understand that this is a problem, but since I am still new to this, I am having a hard time coming up with a solution in an elegant way without making the program unnecessarily complex and confusing. In this example, I have code at parity_flag_set and aux_flag_set which calls printf and thus clears out the registers that I want. Is this just because I need to be using memory and cannot effectively accomplish this with registers only?

Thank you.


There’s a general principle called structured programming. It is the first thing in programming that is taught in a university but it’s not common to pay much attention to it when discussing assembly programming.

The principle makes code clearer in a language-independent manner. You just have to stick with three basic code structures: sequence, selection and iteration. Sequence is what asm gives you by its nature. Selection can be implemented by code snippets like the one revolution shows. Iteration is also easy to implement. Combining three of them lets one make a program of potentially infinite complexity.

The basic idea is that your code should consist of such pieces and all the jumps should be made within them (maybe at different levels). Later you start to see in which cases breaking the rules is good: mostly error handling.
Post 02 Mar 2018, 13:14
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 2651
Location: dank orb

BT and TEST can be used to signal without effecting the source. Instead of AND/CMP/JZ, use TEST/JNZ or BT/JC. These instruction can also be used on memory directly - allowing you to load into registers only what you need there.

Multiway branches and filters are also possible.

Personally, I came by my understanding through a study of logic gates for electronics, and reading the code of others. Boolean algebra is similarly related.
Post 03 Mar 2018, 00:42
View user's profile Send private message Visit poster's website Reply with quote
yeohhs



Joined: 19 Jan 2004
Posts: 168
Location: N 5.43564° E 100.3091°

Re: General Assembly Control Flow Tips


moveax41h wrote:

Are there any good books or resources on how to properly structure your assembly program to avoid these kinds of pitfalls? I obviously understand that this is a problem, but since I am still new to this, I am having a hard time coming up with a solution in an elegant way without making the program unnecessarily complex and confusing. In this example, I have code at parity_flag_set and aux_flag_set which calls printf and thus clears out the registers that I want. Is this just because I need to be using memory and cannot effectively accomplish this with registers only?
Thank you.



Chapter 5 Procedures and Chapter 6 Conditional Processing in Kip R. Irvine's book "Assembly Language for x86 Processors (7th Edition)" might be useful to you. There is also Chapter 8 Advanced Procedures.

_________________
“It’s not that we have a short time to live, but that we waste a lot of it.”
-Lucius Annaeus Seneca
Post 03 Mar 2018, 12:34
View user's profile Send private message Visit poster's website Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 20

Wow, thanks for all of the useful info everyone. Learned a ton and also got this thing working properly. Smile

bitRAKE, I appreciate the instruction suggestions... This is the best way to learn - to see exactly why/how an instruction can be used in place of others.

Just read some about Structured programming as well. Will check out Kip Irvine's book. Fun stuff.
Post 04 Mar 2018, 00:39
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 1117

I suggest you indent your blocks just like in a HLL, makes it much easier to see IMO. Using revolution's example:

Code:
  cmp one_thinganother_thing
  jz .test1_equal
    ; test1 not equal path
    ; ...
    jmp .test1_done
  .test1_equal:
    ; test1 equal path
    ; ...
.test1_done:
  blah

Roughly translates to an if...else block.
Post 04 Mar 2018, 22:17
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 231
Location: Belarus


Furs wrote:
I suggest you indent your blocks just like in a HLL, makes it much easier to see IMO. Using revolution's example:

Code:
  cmp one_thinganother_thing
  jz .test1_equal
    ; test1 not equal path
    ; ...
    jmp .test1_done
  .test1_equal:
    ; test1 equal path
    ; ...
.test1_done:
  blah

Roughly translates to an if...else block.


I’d say it would turn the amazing smart tabs feature of FASM editor into a useless and stupid feature that comes on your way whenever you try to use it.

Unlike HLLs, in asm it is quite important to see clearly where the operands are and where the instruction mnemonic is. I guess, that’s why it is traditional to write asm code in several columns (Fortran might be yet another reason). Typical code blocks for selection and iteration are easily recognizable unless the whole program is a single pile of instructions.
Post 05 Mar 2018, 16:13
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2018, Tomasz Grysztar.
Powered by rwasa.