====================================================== Using global variables to communicate with subprograms [TOC] ====================================================== With subprogram we already can program something useful. As a proof of concept I show you a program that reads in an integer, prints some string an then prints the integer: ---- CODE (type=text) ---------------------------------------------------------- theon$ ulm subprog_io_stuff 123 You typed: 123 theon$ -------------------------------------------------------------------------------- C code can be used as pseudo code to describe our assembly programs. This will reflect what part of the C programming language we currently can implement with assembly code ourself. And vice verse, it gives you an idea of the assembly code the C compiler could generate for you if you use these features of the C programming language. The program `subprog_io_stuff` can be described in such a C pseudo code style as follows: ---- CODE (file=session10/subprog/subprog_io_stuff.c) -------------------------- // for passing an argument and receiving a return value uint64_t arg; void getui() { // implementation of subprogram getui } void puts() { // implementation of subprogram puts } void putui() { // implementation of subprogram putui } // some string (array of characters) char msg[] = "You typed: "; void main() { // local variable uint64_t n; // call subprogram getui, copy return value to local variable getui(); n = arg; // copy pointer to string literal to arg, call puts arg = msg; puts(); // copy local variable to arg, call putui arg = n; putui(); } -------------------------------------------------------------------------------- Exercise: It will actually compile and work =========================================== The above code can be slightly modified such that it compiles with `gcc` and the executable will work, i.e read in an unsigned 64-bit integer, print the string "You typed: " and then prints the integer followed by a newline. Apply the following modifications: - The type `uint64_t` is not a builtin type in C. Usually you have to include `` for getting the proper type definition for an architecture. Insert the following line to the begin of the source file: ---- CODE (type=c) ----------------------------------------------------------- typedef unsigned long uint64_t; ------------------------------------------------------------------------------ This is the proper type definition for `theon`. - Insert implementations for the subprograms. These will consist of calling functions that are defined in the C library that will be linked after the compilation. In the function body of `getui` insert the line ---- CODE (type=c) ----------------------------------------------------------- scanf("%lu", &arg); ------------------------------------------------------------------------------ this function receives two parameters: a pointer to a (format) string and a pointer to the global variable `arg`. In the function body of `puts` insert the line ---- CODE (type=c) ----------------------------------------------------------- printf("%s", arg); ------------------------------------------------------------------------------ In the function body of `putui` insert the line ---- CODE (type=c) ----------------------------------------------------------- printf("%lu", arg); ------------------------------------------------------------------------------ After these modifications the code should compile (bravely ignore a few warnings): ---- SHELL (path=session10/subprog, fold) -------------------------------------- gcc -o subprog_io_stuff subprog_io_stuff_gcc.c -------------------------------------------------------------------------------- Afterwards run the executable `subprog_io_stuff`. Exercise: Understanding the assembly implementation for the ULM =============================================================== The following assembly program is an "equivalent" implementation of the above C program for the ULM. Look at the implementation of `main`, understand the details that are hidden by the C programming language, e.g copying a global variable to a local variable, calling a subprogram and returning from a subprogram. :import: session10/subprog/subprog_io_stuff.s [fold] Copying the global variable to the local variable ------------------------------------------------- Use a picture like that as guide: ---- TIKZ ---------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \renewcommand\MemCellWidth {0.6} \DrawMemArrayOpen{0}{10} \DrawMemLabel{1}{arg} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[orange!50]{1}{9}{global variable arg} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{4}{memory location of global variable arg} \par\endgroup \DrawMemArrayOpen{14}{24} \DrawMemLabel{15}{\%SP} \DrawMemLabel{23}{\%FP} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[red!50]{15}{23}{local variable} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{18}{memory location of local variable} \par\endgroup \end{tikzpicture} -------------------------------------------------------------------------------- The global variable has the label `arg` which is the address of its memory location. The address of the local variable is `%FP - 8`. So with ---- CODE (type=s) ------------------------------------------------------------- ldzwq arg, %4 movq (%4), %4 -------------------------------------------------------------------------------- You first load the address of the global variable and then the global variable itself into register `%4`. From there you can copy the value of the global variable to the memory location of the local variable with ---- CODE (type=s) ------------------------------------------------------------- movq %4, -8(%FP) -------------------------------------------------------------------------------- Copying the local variable to the global variable ------------------------------------------------- Here you need two registers, one for fetching the local variable and one for storing the label of the global variable: ---- CODE (type=s) ------------------------------------------------------------- movq -8(%FP),%4 ldzwq arg, %5 movq %4, (%5) -------------------------------------------------------------------------------- Copying the pointer to a string to a global variable ---------------------------------------------------- For using the `puts` subprogram you first have to copy the address of a string, i.e. a pointer to the string, into the global variable. --- TIKZ ----------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \renewcommand\MemCellWidth {0.6} \DrawMemArrayOpen{0}{10} \DrawMemLabel{1}{arg} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[orange!50]{1}{9}{global variable arg} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{4}{memory location of global variable arg} \par\endgroup \DrawMemArrayOpen{14}{24} \DrawMemLabel{15}{msg} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[orange!50]{15}{23}{"You typed:"} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{18}{memory location of string characters} \par\endgroup \end{tikzpicture} -------------------------------------------------------------------------------- With ---- CODE (type=s) ------------------------------------------------------------- ldzwq msg, %4 -------------------------------------------------------------------------------- you copy the address of the first character of the string into register `%4`, i.e. now `%4` points to the string. Then you copy this address to the memory location of the global variable: ---- CODE (type=s) ------------------------------------------------------------- ldzwq arg, %5 movq %4, (%5) -------------------------------------------------------------------------------- The memory location of the global variable can now be interpreted as a pointer to the string. ---- TIKZ ---------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \renewcommand\MemCellWidth {0.6} \DrawMemArrayOpen{0}{10} \DrawMemLabel{1}{arg} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[orange!50]{1}{9}{global variable arg} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{4}{memory location of global variable arg} \par\endgroup \DrawMemArrayOpen{14}{24} \DrawMemLabel{15}{msg} \begingroup \renewcommand\PaddingMemVariable {0.01} \DrawMemVariable[orange!50]{15}{23}{"You typed:"} \renewcommand\PaddingMemVariable {0.05} \renewcommand\PointerDisplaceY {2} \DrawAnnotateMemCellAbove{18}{memory location of string characters} \par\endgroup \DrawMemPointer{5}{15} \end{tikzpicture} -------------------------------------------------------------------------------- # Examples and exercises on: Using global and local variables # =========================================================== # # # Copy a global variable to a global variable # ------------------------------------------- # In C the you would express this example by # # ---- CODE (file=session10/vars) ------------------------------------------------ # int64_t a = 42; # int64_t b; # # void # main() # { # b = a; // it is about this statement # } # -------------------------------------------------------------------------------- # # This code describes two global variables `a` and `b`. Because `a` is initialized # it is in the data segment, and because `b` is not initialized it is in BSS # segment (so `b` will be zero when the program gets executed). In the assembly # code you would somewhere have this fragment for the global variable `a` # # ----- CODE (type=s) ------------------------------------------------------------ # .data # .align 8 # a .quad 42 # -------------------------------------------------------------------------------- # # And this for the global variable `b` # # ----- CODE (type=s) ------------------------------------------------------------ # .bss # .align 8 # b .space 8 # -------------------------------------------------------------------------------- # # We can describe these two variables at the moment when the execution begins with # the following sketch # # ---- TIKZ ---------------------------------------------------------------------- # \begin{tikzpicture} # \input{memory.tex} # # \renewcommand\MemCellWidth { 0.6} # # \DrawMemArrayOpen{0}{12} # \DrawMemArrayOpen{16}{28} # # \DrawMemLabel{2}{a} # \DrawMemLabel{18}{b} # # \DrawQuadVariable[orange!40]{2}{42} # \DrawQuadVariable[blue!40]{18}{0} # # \end{tikzpicture} # -------------------------------------------------------------------------------- # # On the ULM you need 4 instructions for this, for example # # ----- CODE (type=s) ------------------------------------------------------------ # ldzwq a, %4 # ldzwq b, %5 # movq (%4), %4 # movq %4, (%5) # -------------------------------------------------------------------------------- # # The first two instructions load the addresses for the global variables into two # registers, so after that you have # # ---- TIKZ ---------------------------------------------------------------------- # \begin{tikzpicture} # \input{memory.tex} # # \renewcommand\MemCellWidth { 0.6} # # \DrawMemArrayOpen{0}{12} # \DrawMemArrayOpen{16}{28} # # \DrawMemLabel{2}{a} # \DrawMemLabel{18}{b} # # \DrawQuadVariable[orange!40]{2}{42} # \DrawQuadVariable[blue!40]{18}{0} # # \DrawPointer{2}{\%4} # \DrawPointer{18}{\%5} # # \end{tikzpicture} # -------------------------------------------------------------------------------- # # The third instruction (i.e. `movq (%4), %4`) overwrite register `%4` with the # value of the global variable `a` and the last actually overwrite the global # variable $b$ with it. So after # # ----- CODE (type=s) ------------------------------------------------------------ # movq (%4), %4 # movq %4, (%5) # -------------------------------------------------------------------------------- # # you have # # ---- TIKZ ---------------------------------------------------------------------- # \begin{tikzpicture} # \input{memory.tex} # # \renewcommand\MemCellWidth { 0.6} # # \DrawMemArrayOpen{0}{12} # \DrawMemArrayOpen{16}{28} # # \DrawMemLabel{2}{a} # \DrawMemLabel{18}{b} # # \DrawQuadVariable[orange!40]{2}{42} # \DrawQuadVariable[blue!40]{18}{42} # # \end{tikzpicture} # --------------------------------------------------------------------------------