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

14. External Functions

Jo Van Hoey1 
(1)
Hamme, Belgium
 

We already know how to create and use functions in our source code. But the functions do not have to reside in the same file as our main program. We can write and assemble these functions in a separate file and link them in when building the program. The function printf, which we already used several times, is an example of an external function. In the source file where you plan to use the external function, you declare it with the keyword extern , and the assembler knows it does not have to look for the source of the function. The assembler will assume that the function is already assembled in an object file. The external function will be inserted by the linker, provided it can find it in an object file.

Similar to using C functions such as printf, you can build your own set of functions and link them when you need them.

Building and Linking Functions

Listing 14-1 shows an example program, with three source files, to be saved as separate files: function4.asm, circle.asm, and rect.asm. There is also a new makefile. Study it carefully.
; function4.asm
extern printf
extern c_area
extern c_circum
extern r_area
extern r_circum
global pi
section .data
      pi         dq    3.141592654
      radius     dq    10.0
      side1      dq    4
      side2      dq    5
      fmtf  db   "%s %f",10,0
      fmti  db   "%s %d",10,0
      ca    db   "The circle area is ",0
      cc    db   "The circle circumference is ",0
      ra    db   "The rectangle area is ",0
      rc    db   "The rectangle circumference is ",0
section .bss
section .text
      global main
main:
push  rbp
mov   rbp,rsp
; circle area
      movsd  xmm0, qword [radius]    ; radius xmm0 argument
      call   c_area                  ; area returned in xmm0
      ; print the circle area
            mov   rdi, fmtf
            mov   rsi, ca
            mov   rax, 1
            call  printf
; circle circumference
      movsd      xmm0, qword [radius] ; radius xmm0 argument
      call  c_circum                  ; circumference in xmm0
      ; print the circle circumference
            mov   rdi, fmtf
            mov   rsi, cc
            mov   rax, 1
            call  printf
; rectangle area
      mov   rdi, [side1]
      mov   rsi, [side2]
      call  r_area               ; area returned in rax
      ; print the rectangle area
            mov   rdi, fmti
            mov   rsi, ra
            mov   rdx, rax
            mov   rax, 0
            call  printf
; rectangle circumference
      mov   rdi,  [side1]
      mov   rsi,  [side2]
      call  r_circum             ; circumference in rax
      ; print the rectangle circumference
            mov   rdi, fmti
            mov   rsi, rc
            mov   rdx, rax
            mov   rax, 0
            call  printf
mov rsp,rbp
pop rbp
ret
Listing 14-1

function4.asm

In the above source, we declared a number of functions as external , as we already did several times before when using printf . There’s nothing new here. But we also declared the variable pi to be global . That means this variable will also be available to external functions.

Listing 14-2 and Listing 14-3 show separate files that contain only functions.
; circle.asm
extern pi
section .data
section .bss
section .text
;------------------------------------------------
global c_area
c_area:
      section .text
      push rbp
      mov rbp,rsp
            movsd xmm1, qword [pi]
            mulsd xmm0, xmm0       ;radius in xmm0
            mulsd xmm0, xmm1
      mov rsp,rbp
      pop rbp
      ret
;------------------------------------------------
global c_circum
c_circum:
      section .text
      push rbp
      mov rbp,rsp
            movsd xmm1, qword [pi]
            addsd xmm0, xmm0        ;radius in xmm0
            mulsd xmm0, xmm1
      mov rsp,rbp
      pop rbp
      ret
Listing 14-2

circle.asm

; rect.asm
section .data
section .bss
section .text
;------------------------------------------------
global r_area
r_area:
      section .text
      push rbp
      mov rbp,rsp
            mov   rax, rsi
            imul  rax, rdi
            mov   rsp,rbp
      pop rbp
      ret
;------------------------------------------------
global r_circum
r_circum:
      section .text
      push rbp
      mov rbp,rsp
            mov   rax, rsi
            add   rax, rdi
            add   rax, rax
      mov rsp,rbp
      pop rbp
      ret
Listing 14-3

rect.asm

In circle.asm we want to use the variable pi declared in the main source file as global, which is by the way not a good idea, but we are doing it here for demonstration purposes. Global variables such as pi are difficult to keep track of and could even lead to conflicting variables with the same names. It is best practice to use registers to pass values to a function. Here, we have to specify that pi is external. circle.asm and rect.asm each have two functions, one for computing the circumference and one for computing the area. We have to indicate that these functions are global, similar to the main program. When these functions are assembled, the necessary “overhead” is added, enabling the linker to add these functions to other object code.

Expanding the makefile

To make all this work, we need an expanded makefile , as shown in Listing 14-4.
# makefile for function4, circle and rect.
function4: function4.o circle.o rect.o
      gcc -g -o function4 function4.o circle.o rect.o -no-pie
function4.o: function4.asm
      nasm -f elf64 -g -F dwarf function4.asm -l function4.lst
circle.o: circle.asm
      nasm -f elf64 -g -F dwarf circle.asm -l circle.lst
rect.o: rect.asm
      nasm -f elf64 -g -F dwarf rect.asm -l rect.lst
Listing 14-4

makefile

You read the makefile from the bottom up: first the different assembly source files are assembled into object files, and then the object files are linked together in function4, the executable. You can see here the power of using make. When you modify one of the source files, make knows, thanks to the tree structure, which files to re-assemble and link. Of course, if your functions are stable and will not change anymore, there is no need to try to re-assemble them in every makefile. Just store the object file somewhere in a convenient directory and refer to that object file with its complete path in the gcc line of the makefile. An object file is the result of assembling or compiling source code. It contains machine code and also information for a linker about which global variables and external functions are needed in order to produce a valid executable. In our case, the object files all reside in the same directory as our main source, so no paths were specified here.

What about the printf function? Why is no reference made to printf in the makefile? Well, gcc is smart enough to also check C libraries for functions that are referenced in the source code. This means you should not use the names of C functions for naming your own functions! That will confuse everybody, not to mention your linker.

In the code, we used registers to transfer values from the main program to the functions, and vice versa, and that is best practice. For example, before calling r_area, we moved side1 to rdi and side2 to rsi. Then we returned the computed area in rax. To return the result, we could have used a global variable, similar to pi in the section .data section of main. But as we said before, that should be avoided. In the next chapter on calling conventions, we will discuss this more in detail.

Figure 14-1 shows the output of this program.
../images/483996_1_En_14_Chapter/483996_1_En_14_Fig1_HTML.jpg
Figure 14-1

Output of function4

When using this example in SASM, you have to assemble the external functions first to obtain object files. Then on the SASM Settings dialog’s Build tab, you need to add the location of these object files in the Linking Options line. The Linking Options line would look like the following in this case (be careful not to introduce unwanted spaces in this line!):
      $PROGRAM.OBJ$ -g -o $PROGRAM$ circle.o rect.o -no-pie

Summary

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

  • How to global variables

  • How to use the makefile and external functions

  • How to transfer values to and from functions

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

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