© Jo Van Hoey 2019
J. Van HoeyBeginning x64 Assembly Programminghttps://doi.org/10.1007/978-1-4842-5076-1_7

7. Jumping and Looping

Jo Van Hoey1 
(1)
Hamme, Belgium
 

You will agree that a visual debugger such as DDD is quite useful, especially for investigating large programs. In this chapter, we will introduce SASM (for SimpleASM). It is an open source, cross-platform integrated development environment (IDE). It features syntax highlighting and graphical debugging. It’s a fantastic tool for an assembler programmer!

Installing SimpleASM

Go to https://dman95.github.io/SASM/english.html , select the version for your OS, and install it. For Ubuntu 18.04, go into the directory xUbuntu_18.04/amd64/ and download and install the sasm_3.10.1_amd64.deb package with the following command:
sudo dpkg -i sasm_3.10.1_amd64.deb
If you get an error message about dependency problems, install the missing packages and retry the installation of SASM. You can also try the following:
sudo apt --fix-broken install

This will normally install all the required missing packages.

Using SASM

Start SASM by typing sasm at the CLI and choose your language. SASM starts, and if you see an error on the CLI such as Failed to load module "canberra-gtk-module", install the following packages:
      sudo apt install libcanberra-gtk*

A bunch of files will be installed, and you won’t see the error anymore.

In SASM, go to the Settings dialog, as shown in Figure 7-1. On the Common tab, select Yes for “Show all registers in debug.”
../images/483996_1_En_7_Chapter/483996_1_En_7_Fig1_HTML.jpg
Figure 7-1

SASM Settings dialog, Common tab

On the Build tab, modify the settings as shown in Figure 7-2.
../images/483996_1_En_7_Chapter/483996_1_En_7_Fig2_HTML.jpg
Figure 7-2

SASM Settings dialog, Build tab

Be very careful here, because the settings have to be exactly as shown in the figure; one space too many, even hidden at the end of a line, and SASM will not do what you want. When you are ready, click the OK button and restart SASM.

When you start a new project with SASM, you will find some default code already in the editor window. We will not use that code, so you can delete it. At the CLI, type the following:
      sasm jump.asm

If jump.asm does not exist, SASM will start with a new editor window; just delete the default code. If the file exists, it will open in the editor window.

Listing 7-1 shows the code for jump.asm.
; jump.asm
extern printf
section .data
      number1    dq    42
      number2    dq    41
      fmt1  db   "NUMBER1 > = NUMBER2",10,0
      fmt2  db   "NUMBER1 < NUMBER2",10,0
section .bss
section .text
      global     main
main:
      push  rbp
      mov   rbp,rsp
      mov   rax, [number1]   ; move the numbers into registers
      mov   rbx, [number2]
      cmp   rax,rbx    ; compare rax and rbx
      jge   greater    ; rax greater or equal go to greater:
mov   rdi,fmt2         ; rax is smaller, continue here
mov   rax,0            ; no xmm involved
      call  printf     ; display fmt2
      jmp   exit       ; jump to label exit:
greater:
      mov   rdi,fmt1   ; rax is greater
      mov   rax,0      ; no xmm involved
      call  printf     ; display fmt1
exit:
      mov   rsp,rbp
      pop   rbp
      ret
Listing 7-1

jump.asm

Copy the code into the SASM editor window; by default SASM will use syntax highlighting. When you are finished typing, hit the green triangle icon at the top, which means “run.” If everything goes correctly, you will see your output in the Output area, as shown in Figure 7-3.
../images/483996_1_En_7_Chapter/483996_1_En_7_Fig3_HTML.jpg
Figure 7-3

SASM output

When you save a file in SASM, the source code will be saved. If you want to save the executable, you need to choose Save.exe in the File menu.

To start debugging, click in the numbered left margin to the left of the main: label. This will put a red circle between the main: label and its line number. This is a breakpoint. Then at the top click the green triangle with the bug on it. In the top menu, choose Debug and select Show Registers and Show Memory. A number of additional windows will appear on your screen: Registers, Memory, and also a GDB command-line widget.

With the Step icons, you can now walk through the code and see how the register values change. To investigate how a variable changes, right-click the variable declaration in section .data and choose Watch. The variable will be added in the Memory window, and SASM tries to guess the type. If the value displayed by SASM is not as expected, change the type manually to the proper format. When debugging with SASM, the following line of code is added for correct debugging:
mov rbp, rsp; for correct debugging

This line can confuse other debuggers such as GDB, so make sure to remove it from the code before you run GDB separately from the CLI.

In the SASM menu Settings ➤ Common, make sure to select Yes for “Show all registers in debug.” When debugging in SASM, scroll down in the register window. At the bottom you will see 16 ymm registers, each with two values between parentheses. The first value is the corresponding xmm register. We will explain these registers in more detail when we talk about SIMD.

By the way, Figure 7-4 shows the output on the screen after building and running the program as we did before.
../images/483996_1_En_7_Chapter/483996_1_En_7_Fig4_HTML.jpg
Figure 7-4

Output from jump.asm

In the program we use a compare instruction cmp and two jump instructions, jge and jmp. The cmp instruction is what is called a conditional instruction. Here cmp compares two operands, in this case two registers. One of the two operands can also be a memory operand, and the second operand can be an immediate value. In any case, the size of the two operands must be the same (byte, word, and so on). The cmp instruction will set or clear flags in the flag register.

The flags are bits located in the rflags register that can be set to 1 or cleared to 0, depending on a number of conditions. Important in our case are the zero flag (ZF), the overflow flag (OF), and the sign flag (SF). You can use your debugger to examine these and other flags. With SASM you can easily see what is happing to all the registers, including the flag register, called eflags in SASM. Different values in the cmp operands will result in different flags being set or cleared. Experiment a little bit with the values to see what is happening with the flags.

If you want to use the flags, you have to evaluate them immediately after the cmp instruction. If you execute other instructions before you evaluate rflags, the flags may have been changed. In our program we evaluate the flags with jge , meaning “jump if greater than or equal.” If the condition is met, the execution jumps to the label following the jge instruction. If the condition is not met, execution continues with the instruction just after the jge instruction. Table 7-1 lists some of the usual conditions, but you can hunt for more details in the Intel manuals.
Table 7-1

Jump Instructions and Flags

Instruction

Flags

Meaning

Use

je

ZF=1

Jump if equal

Signed, unsigned

jne

ZF=0

Jump if not equal

Signed, unsigned

jg

((SF XOR OF) OR ZF) = 0

Jump if greater

Signed

jge

(SF XOR OF) = 0

Jump if greater or equal

Signed

jl

(SF XOR OF) = 1

Jump if lower

Signed

jle

((SF XOR OF) OR ZF) = 1

Jump if lower or equal

Signed

ja

(CF OR ZF) = 0

Jump if above

Unsigned

jae

CF=0

Jump if above or equal

Unsigned

jb

CF=1

Jump if lesser

Unsigned

jbe

(CF OR ZF) = 1

Jump if lesser or equal

Unsigned

In our program we have also an unconditional jump instruction, jmp . If the program execution hits this instruction, the program jumps to the label specified after jmp, regardless of flags or conditions.

A more complicated form of jumping is looping , which means repeating a set of instructions until a condition is met (or is not met). Listing 7-2 shows an example.
; jumploop.asm
extern printf
section .data
      number      dq    5
      fmt         db    "The sum from 0 to %ld is %ld",10,0
section .bss
section .text
      global main
main:
      push  rbp
      mov   rbp, rsp
      mov   rbx,0            ; counter
      mov   rax,0            ; sum will be in rax
jloop:
      add   rax, rbx
      inc   rbx
      cmp   rbx,[number]     ; number already reached?
      jle   jloop            ; number not reached yet, loop
                             ; number reached, continue here
      mov   rdi,fmt          ; prepare for displaying
      mov   rsi, [number]
      mov   rdx,rax
      mov   rax,0
      call  printf
      mov   rsp,rbp
      pop   rbp
      ret
Listing 7-2

jumploop.asm

The program adds all the numbers from 0 to the value in number. We use rbx as a counter and rax to keep track of the sum. We created a loop, which is the code between jloop: and jle jloop. In the loop, we add the value in rbx to rax, increase rbx with 1, and then compare if we have reached the end (number). If we have in rbx a value lower than or equal to number, we restart the loop; otherwise, we continue with the instruction after the loop and get ready to print the result. We used an arithmetic instruction, inc, to increase rbx. We will discuss arithmetic instructions in later chapters.

Listing 7-3 shows another way to write a loop.
; betterloop
extern printf
section .data
      number      dq    5
      fmt         db    "The sum from 0 to %ld is %ld",10,0
section .bss
section .text
      global main
main:
      push  rbp
      mov   rbp,rsp
      mov   rcx,[number]    ; initialize rcx with number
      mov   rax, 0
bloop:
      add   rax,rcx         ; add rcx to sum
      loop  bloop           ; loop while decreasing rcx with 1
                            ; until rcx = 0
      mov   rdi,fmt         ; rcx = 0, continue here
      mov   rsi, [number]   ; sum to be displayed
      mov   rdx, rax
      mov   rax,0           ; no floating point
      call  printf          ; display
      mov   rsp,rbp
      pop   rbp
      ret
Listing 7-3

betterloop.asm

Here you see that there is a special loop instruction that uses rcx as a decreasing loop counter. With every pass through the loop, rcx is decreased automatically, and as long as rcx is not equal to 0, the loop is executed again. That’s less code to type.

An interesting experiment is to put 1000000000 (a one and nine zeros) in number and then rebuild and run the two previous programs. You can time the speed with the Linux time command, as shown here:
      time ./jumploop
      time ./betterloop
Note that betterloop is slower than jumploop (see Figure 7-5)! Using the loop instruction is convenient but comes at a price in terms of execution performance. We used the Linux time instruction to measure the performance; later we will show more appropriate ways to investigate and tune program code.
../images/483996_1_En_7_Chapter/483996_1_En_7_Fig5_HTML.png
Figure 7-5

Looping versus jumping

You may wonder why we bothered to use DDD when there is a tool such as SASM. Well, you will see Iater that in SASM you cannot investigate the stack, but you can with DDD. We will return to DDD later.

Summary

In this chapter, you learned the following:
  • How to use SASM

  • How to use jump instructions

  • How to use the cmp instruction

  • How to use the loop instruction

  • How to evaluate flags

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.153.212