Chapter 14
Page 308
-
# sum9Ints.s # Sums the integers 1 - 9. .intel_syntax noprefix # Stack frame # passing arguments on stack (rsp) # need 9x8 = 72 -> 80 bytes .equ first,0 .equ second,8 .equ third,16 .equ fourth,24 .equ fifth,32 .equ sixth,40 .equ seventh,48 .equ eighth,56 .equ ninth,64 .equ argSize,-80 # local vars (rbp) # need 10x4 = 40 -> 48 bytes for alignment .equ i,-4 .equ h,-8 .equ g,-12 .equ f,-16 .equ e,-20 .equ d,-24 .equ c,-28 .equ b,-32 .equ a,-36 .equ total,-40 .equ localSize,-48 # Read only data .section .rodata format: .string "The sum is %i\n" # Code .text .globl main .type main, @function main: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr a[rbp], 1 # initialize values mov dword ptr b[rbp], 2 # etc... mov dword ptr c[rbp], 3 mov dword ptr d[rbp], 4 mov dword ptr e[rbp], 5 mov dword ptr f[rbp], 6 mov dword ptr g[rbp], 7 mov dword ptr h[rbp], 8 mov dword ptr i[rbp], 9 add rsp, argSize # space for arguments mov eax, i[rbp] # load i mov ninth[rsp], rax # 9th argument mov eax, h[rbp] # load h mov eighth[rsp], rax # 8th argument mov eax, g[rbp] # load g mov seventh[rsp], rax # 7th argument mov eax, f[rbp] # load f mov sixth[rsp], rax # 6th argument mov eax, e[rbp] # load e mov fifth[rsp], rax # 5th argument mov eax, d[rbp] # load d mov fourth[rsp], rax # 4th argument mov eax, c[rbp] # load c mov third[rsp], rax # 3rd argument mov eax, b[rbp] # load b mov second[rsp], rax # 2nd argument mov eax, a[rbp] # load a mov first[rsp], rax # 1st argument call addNine sub rsp, argSize # remove arguments mov total[rbp], eax # total = sumNine(...) mov esi, total[rbp] # show result lea rdi, format[rip] mov eax, 0 call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
# addNine.s # Sums nine integer arguments and returns the total. .intel_syntax noprefix # Calling sequence: # push one # push two # push three # push four # push five # push six # push seven # push eight # push nine # returns sum # Stack frame # arguments in stack frame .equ one,16 .equ two,24 .equ three,32 .equ four,40 .equ five,48 .equ six,56 .equ seven,64 .equ eight,72 .equ nine,80 # local variables .equ total,-4 .equ localSize,-16 # Code .text .globl addNine .type addNine, @function addNine: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov eax, one[rbp] # retrieve one add eax, two[rbp] # add two add eax, three[rbp] # plus three add eax, four[rbp] # plus four add eax, five[rbp] # plus five add eax, six[rbp] # plus six add eax, seven[rbp] # plus seven add eax, eight[rbp] # plus eight add eax, nine[rbp] # plus nine mov rsp, rbp # restore stack pointer pop rbp # and caller framee pointer ret
-
# sumRange.s # Sums the integers 1 - 9. .intel_syntax noprefix # Stack frame # local vars (rbp) .equ nLow,-4 .equ nHigh,-8 .equ total,-12 .equ localSize,-16 # Read only data .section .rodata readFormat: .string "%i" lowerFormat: .string "Enter lower number: " higherFormat: .string "Enter higher number: " result: .string "Sum of all integers between them = %i\n" # Code .text .globl main .type main, @function main: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. lea rdi, lowerFormat[rip] # ask for lower number mov eax, 0 call printf@plt lea rsi, nLow[rbp] # get lower number lea rdi, readFormat[rip] mov eax, 0 call __isoc99_scanf@plt lea rdi, higherFormat[rip] # ask for higher number mov eax, 0 call printf@plt lea rsi, nHigh[rbp] # get higher number lea rdi, readFormat[rip] mov eax, 0 call __isoc99_scanf@plt mov esi, nHigh[rbp] # nHigh mov edi, nLow[rbp] # nLow call addRange mov total[rbp], eax # total = sumNine(...) mov esi, total[rbp] # show result lea rdi, result[rip] mov eax, 0 call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
# addRange.s # Sums all integers between two integers and returns the total. .intel_syntax noprefix # Calling sequence: # edi <- lower number # esi <- higher number # returns sum # Code .text .globl addRange .type addRange, @function addRange: push rbp # save frame pointer mov rbp, rsp # set new frame pointer mov eax, edi # start with lower number while: cmp edi, esi # are we there? jge allDone # yes, all done inc edi # no, next integer add eax, edi # add it in to total jmp while # and continue allDone: mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
-
Don’t forget that we need C header files for our
writeStr
andreadLn
assembly language functions so we can call them from C. We’ll be using thewriteStr
andreadLn
functions in subsequent programs, so make sure that you get them to work correctly. I have placed the files in acommon
directory on my computer, and I link to them in any project directory that uses them. This avoids having multiple copies that may get out of sync./* echo.c * Prompts user to enter text and echos it. */ #include "writeStr.h" #include "readLn.h" #define MAX 5 int main(void) { char text[MAX]; writeStr("Enter some text: "); readLn(text, MAX); writeStr("You entered: "); writeStr(text); writeStr("\n"); return 0; }
/* writeStr.h * C header file for writeStr assembly language function * Writes a C-style text string to the standard output (screen). * Calling sequence: * rdi <- address of string to be written * call writestr * returns number of characters written */ #ifndef WRITESTR_H #define WRITESTR_H int writeStr(char *); #endif
# writeStr.s # Writes a C-style text string to the standard output (screen). # Calling sequence: # rdi <- address of string to be written # call writestr # returns number of characters written .intel_syntax noprefix # Useful constants .equ STDOUT,1 .equ NUL,0 # Stack frame, showing local variables and arguments .equ stringAddr,-16 .equ count,-4 .equ localSize,-16 .text .globl writeStr .type writeStr, @function writeStr: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov stringAddr[rbp], rdi # save string pointer mov dword ptr count[rbp], 0 # count = 0; writeLoop: mov rax, stringAddr[rbp] # get current pointer cmp byte ptr [rax], NUL # at end yet? je done # yes, all done mov edx, 1 # no, write one character mov rsi, rax # points to current char mov edi, STDOUT # on the screen call write@plt inc dword ptr count[rbp] # count++; inc qword ptr stringAddr[rbp] # stringAddr++; jmp writeLoop # and check for end done: mov eax, count[rbp] # return total; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
/* readLn.h * C header file for readLn assembly language function * Reads a line (through the '\n' character from standard input. Deletes * the '\n' and creates a C-style text string. * Calling sequence: * rsi <- length of char array * rdi <- address of place to store string * call readLn * returns number of characters read (not including NUL) */ #ifndef READLN_H #define READLN_H int readLn(char *, int); #endif
# readLn.s # Reads a line (through the '\n' character from standard input. Deletes # the '\n' and creates a C-style text string. # Calling sequence: # rsi <- length of char array # rdi <- address of place to store string # call readLn # returns number of characters stored (not including NUL) .intel_syntax noprefix # Useful constant .equ STDIN,0 # Stack frame, showing local variables and arguments .equ maxLength,-24 .equ stringAddr,-16 .equ count,-4 .equ localSize,-32 .text .globl readLn .type readLn, @function readLn: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov maxLength[rbp], rsi # save max storage space mov stringAddr[rbp], rdi # save string pointer mov dword ptr count[rbp], 0 # count = 0; sub dword ptr maxLength[rbp], 1 # room for NUL char mov edx, 1 # read one character mov rsi, stringAddr[rbp] # into storage area mov edi, STDIN # from keyboard call read@plt readLoop: mov rax, stringAddr[rbp] # get pointer cmp byte ptr [rax], '\n' # return key? je endOfString # yes, mark end of string mov eax, count[rbp] # current count cmp maxLength[rbp], eax # is caller's array full? jbe skipStore # yes, don't store inc qword ptr stringAddr[rbp] # no, next byte inc dword ptr count[rbp] # count++; skipStore: mov edx, 1 # get another character mov rsi, stringAddr[rbp] # into storage area mov edi, STDIN # from keyboard call read@plt jmp readLoop # and look at it endOfString: mov rax, stringAddr[rbp] # current pointer mov byte ptr [rax], 0 # mark end of string mov eax, count[rbp] # return total; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
Page 318
-
Counting number of times
addConst
is called.# varLife.s # Compares scope and lifetime of automatic, static, and global variables. .intel_syntax noprefix # Stack frame .equ x,-8 .equ y,-4 .equ localSize,-16 # Useful constants .equ INITx,12 .equ INITy,34 .equ INITz,56 .section .rodata .align 8 tableHead1: .string " automatic static global" tableHead2: .string " x y z" format: .string "In main:%12i %8i %8i\n" # Define global variable .data .align 4 .globl z .type z, @object z: .int INITz # initialize the global # Code .text .globl main .type main, @function main: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr x[rbp], INITx # initialize locals mov dword ptr y[rbp], INITy lea rdi, tableHead1[rip] # print heading call puts@plt lea rdi, tableHead2[rip] call puts@plt mov ecx, z[rip] # print variables mov edx, y[rbp] mov esi, x[rbp] lea rdi, format[rip] mov eax, 0 call printf@plt call addConstCount # add to variables call addConstCount mov ecx, z[rip] # print variables mov edx, y[rbp] mov esi, x[rbp] lea rdi, format[rip] mov eax, 0 call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
# addConst.s # Adds constant to automatic, static, global variables. .intel_syntax noprefix # Stack frame .equ x,-4 .equ localSize,-16 # Useful constants .equ ADDITION,1000 .equ INITx,78 .equ INITy,90 .equ INITn,0 # Constant data .section .rodata .align 8 format: .string "In addConst:%8i %8i %8i called %i times\n" # Define static variables .data .align 4 .type y_addConst, @object y_addConst: .int INITy .type n_addConst, @object n_addConst: .int INITn # Code .text .globl addConstCount .type addConstCount, @function addConstCount: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr x[rbp], INITx # initialize inc dword ptr n_addConst[rip] add dword ptr x[rbp], ADDITION # add to vars add dword ptr y_addConst[rip], ADDITION add dword ptr z[rip], ADDITION mov r8d, n_addConst[rip] mov ecx, z[rip] # print variables mov edx, y_addConst[rip] mov esi, x[rbp] lea rdi, format[rip] mov eax, 0 # no floats call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
-
Two
addConst
functions that have separate static variables.# varLife2.s # Compares scope and lifetime of automatic, static, and global variables. .intel_syntax noprefix # Stack frame .equ x,-8 .equ y,-4 .equ localSize,-16 # Useful constants .equ INITx,12 .equ INITy,34 .equ INITz,56 .section .rodata .align 8 tableHead1: .string " automatic static global" tableHead2: .string " x y z" format: .string "In main: %12i %8i %8i\n" # Define global variable .data .align 4 .globl z .type z, @object z: .int INITz # initialize the global # Code .text .globl main .type main, @function main: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr x[rbp], INITx # initialize locals mov dword ptr y[rbp], INITy lea rdi, tableHead1[rip] # print heading call puts@plt lea rdi, tableHead2[rip] call puts@plt mov ecx, z[rip] # print variables mov edx, y[rbp] mov esi, x[rbp] lea rdi, format[rip] mov eax, 0 call printf@plt call addConst0 # add to variables call addConst1 call addConst0 call addConst1 mov ecx, z[rip] # print variables mov edx, y[rbp] mov esi, x[rbp] lea rdi, format[rip] mov eax, 0 call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret
# addConst2.s # Adds constant to automatic, static, global variables. .intel_syntax noprefix # Stack frame .equ x,-4 .equ localSize,-16 # Useful constants .equ ADDITION0,1000 .equ ADDITION1,2000 .equ INITx,78 .equ INITy,90 .equ INITn,0 # Constant data .section .rodata .align 8 format0: .string "In addConst0:%8i %8i %8i called %i times\n" format1: .string "In addConst1:%8i %8i %8i called %i times\n" # Define static variables .data .align 4 .type y_addConst0, @object y_addConst0: .int INITy .type n_addConst0, @object n_addConst0: .int INITn .type y_addConst1, @object y_addConst1: .int INITy .type n_addConst1, @object n_addConst1: .int INITn # Code .text .globl addConst0 .type addConst0, @function addConst0: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr x[rbp], INITx # initialize inc dword ptr n_addConst0[rip] add dword ptr x[rbp], ADDITION0 # add to vars add dword ptr y_addConst0[rip], ADDITION0 add dword ptr z[rip], ADDITION0 mov r8d, n_addConst0[rip] mov ecx, z[rip] # print variables mov edx, y_addConst0[rip] mov esi, x[rbp] lea rdi, format0[rip] mov eax, 0 # no floats call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret .globl addConst1 .type addConst1, @function addConst1: push rbp # save frame pointer mov rbp, rsp # set new frame pointer add rsp, localSize # for local var. mov dword ptr x[rbp], INITx # initialize inc dword ptr n_addConst1[rip] add dword ptr x[rbp], ADDITION1 # add to vars add dword ptr y_addConst1[rip], ADDITION1 add dword ptr z[rip], ADDITION1 mov r8d, n_addConst1[rip] mov ecx, z[rip] # print variables mov edx, y_addConst1[rip] mov esi, x[rbp] lea rdi, format1[rip] mov eax, 0 # no floats call printf@plt mov eax, 0 # return 0; mov rsp, rbp # restore stack pointer pop rbp # and caller frame pointer ret