Writing a Useful Program With NASM YAN Hongfei Yhf@net.cs.pku.edu.cn Network Group Spring 2003
Overview References Write the first program Write a bigger program helloWorld.asm Improve the above program helloWorld1.asm Write a bigger program showArgs.asm Write a more bigger program textFile.asm linlib.asm
References “Writing a useful program with NASM” NASM Manual http://www.leto.net/papers/writing-a-useful-program-with-nasm.txt NASM Manual available in doc/html directory of source Bookcode of AssemblyLanguageStepByStep Available at http://net.cs.pku.edu.cn/~aoa Paul A. Carter.Tutorial: PC Assembly Language, December 12, 2002. Randall Hyde. The Art of Assembly Language , 2001. Course projects From my students
more /proc/version (redhat 8 or higher) What we need? more /proc/version (redhat 8 or higher) Linux version 2.4.18-14 (gcc version 3.220020903 (Red Hat Linux 8.0 3.2-7)) #1 Wed Sep 3 13:35:50 EDT 2003 nasm -version NASM version 0.98.34 compiled on Jul 23 2002 gcc –version gcc (GCC) 3.2 20020903 (Red Hat Linux 8.0 3.2-7) vi –version VIM – Vi Improved 6.1 (2002 Mar 24, compiled Aug 27 2002 19:07:13)
helloWorld.asm ;; These externals are all from the standard C library: extern printf ; Notify linker that we're calling printf [SECTION .data] ; Section containing initialised data msg db “Hello, world!”, 0xa,0 ;our dear string [SECTION .text] global main ; Required so linker can find entry point main: push dword msg call printf add esp,byte 4 ; Clean up stack after printf call return: mov eax,0 ret ; Return control to Linux Parameters to a subprogram may be passed on the stack. They are pushed onto the stack before the CALL instruction. push dword msg add esp,byte 4 After the subprogram is over, the parameters that were pushed on the stack must be removed. The C calling convention specifies that the caller code must do this.
helloWorld: helloWorld.o gcc -o helloWorld helloWorld.o Makefile helloWorld: helloWorld.o gcc -o helloWorld helloWorld.o helloWorld.o: helloWorld.asm nasm -f elf helloWorld.asm The -f Option: Specifying the Output File Format press "tab" to input it
Improved makefile ASM = nasm –f elf CC = gcc –o all: helloWorld helloWorld: helloWorld.o $(CC) helloWorld helloWorld.o helloWorld.o: helloWorld.asm $(ASM) helloWorld.asm
(gdb) disassemble main gdb helloWorld (gdb) disassemble main Dump of assembler code for function main: 0x8048330 <main>: push $0x8049398 0x8048335 <main+5>: call 0x8048268 <printf> 0x804833a <main+10>: add $0x4,%esp End of assembler dump help disassemble Disassemble a specified section of memory
helloWorld1.asm – improved helloWorld.asm extern printf [SECTION .data] msg db “Hello, world!”, 0xa,0 ;our dear string [SECTION .text] global main main: push ebp mov ebp,esp push dword msg call printf add esp,byte 4 return: mov esp,ebp ; Destroy stack frame before returning pop ebp mov eax,0 ret If the stack is also used inside the subprogram to store data, the number needed to be added to ESP will change. To solve this problem, the 80386 supplies another register to use: EBP.
Improved makefile ASM = nasm –f elf CC = gcc –o all: helloWorld helloWorld1 helloWorld: helloWorld.o $(CC) helloWorld helloWorld.o helloWorld.o: helloWorld.asm $(ASM) helloWorld.asm helloWorld1: helloWorld1.o $(CC) helloWorld1 helloWorld1.o helloWorld1.o: helloWorld1.asm $(ASM) helloWorld1.asm
man(manual) man man man –S 3 printf format and display the on-line manual pages To get a plain text version of a man page man –S 3 printf | col –b > printf.mantxt man –S 3 printf int printf(const char *format, …);
Process memory
$./showArgs 42 A $ ./showArgs 42 A ----------------------- | "A" | argv[2] | "42" | argv[1] NOTE: This is the character "4" and "2", | | not the number 42 ---------------------- |“showArgs" | argv[0] | 3 | The number of arguments, including argv[0], | | which is the program name
Saving registers First, C assumes that a subroutine maintains the values of the following registers: EBX, ESI, EDI, EBP, CS, DS, SS, ES. This does not mean that the subroutine can not change them internally. Instead, it means that if it does change their values, it must restore their original values before the subroutine returns. The EBX, ESI and EDI values must be unmodified because C uses these registers for register variables. The EBX, ESI and EDI values must be unmodified because C uses these registers for register variables. Usually the stack is used to save the original values of these registers.
showArgs.asm $ ./showArgs 42 A Argument0: ./showArgs Argument1: 42 extern printf [SECTION .data] argmsg db "Argument %d: %s",10,0 [SECTION .text] global main main: push ebp mov ebp,esp push ebx ; preserve ebp, ebx, esi, & edi push esi push edi mov edi,[ebp+8] ; Load argument count into edi mov ebx,[ebp+12] ; Load pointer to argument table into ebx xor esi,esi ; Clear esi to 0 .showit: push dword [ebx+esi*4] ; Push address of an arg on the stack push esi push dword argmsg call printf add esp, byte 12 inc esi ; Bump arg number to next arg dec edi ; Decrement arg counter by 1 jnz .showit pop edi ; Restore saved registers pop esi pop ebx mov esp,ebp pop ebp mov eax,0 ret $ ./showArgs 42 A Argument0: ./showArgs Argument1: 42 Argument2: A
Directives 1/2 A directive is an artifact of the assembler not the CPU. They are generally used to either instruct the assembler to do something or inform the assembler of something. They are not translated into machine code. The equ directive HELPLEN EQU 72 The %define directive %define SIZE 100 mov eax, SIZE Macros are more flexible than symbols in two ways. Macros can be redefined and can be more than simple constant numbers.
Directives 2/2 used in data segments to define room for memory. There are two ways memory can be reserved. The first way only defines room for data; L7 resb 1 ; 1 uninitialized byte the second way defines room and an initial value diskhelpnm db “helptextfile.txt”,0 L2 dw 1000 Double quotes and single quotes are treated the same. Consecutive data definitions are stored sequentially in memory.
Local Labels A label beginning with a single period is treated as a local label, which means that it is associated with the previous non-local label. for example: label1 ; some code .loop ; some more code jne .loop ret label2 ; some code
textFile.asm 1/5 ;this program requires several subroutines in an external library named LINLIB.ASM. extern fopen extern fclose extern fgets extern printf extern newline ; Outputs a specified number of newline chars [SECTION .text] global main main: push ebp mov ebp,esp push ebx ; Program must preserve ebp, ebx, esi, & edi push esi push edi mov eax,[ebp+8] cmp eax,1 ; If count is 1, there are no args ja chkarg2 ; Continue if arg count is > 1 mov ebx, dword diskhelpnm ; Put address of help file name in ebx call diskhelp ; If only 1 arg, show help info... jmp gohome ; ...and exit the program ;;;
textFile.asm 2/5 FILE *fopen(const char *path, const char *mode); ;;; chkarg2: gohome: pop edi ; Restore saved registers pop esi pop ebx mov esp,ebp ; Destroy stack frame before returning pop ebp ret ; Return control to to the C shutdown code ;;; SUBROUTINES================================================================ diskhelp: push dword opencode ; Push pointer to open-for-read code "r" push ebx ; Pointer to name of help file is passed in ebx call fopen ; Attempt to open the file for reading add esp,8 ; Clean up the stack cmp eax,0 ; fopen returns null if attempted open failed jne .disk ; Read help info from disk, else from memory call memhelp ret FILE *fopen(const char *path, const char *mode);
textFile.asm 3/5 char *fgets(char *s, int size, FILE *stream); .disk: mov ebx,eax ; Save handle of opened file in ebx .rdln: push ebx ; Push file handle on the stack push dword HELPLEN ; Limit line length of text read push dword helpline ; Push address of help text line buffer call fgets ; Read a line of text from the file add esp,12 ; Clean up the stack cmp eax,0 ; A returned null indicates error or EOF jle .done ; If we get 0 in eax, close up & return push dword helpline ; Push address of help line on the stack call printf ; Call printf to display help line add esp,4 ; Clean up the stack jmp .rdln .done: push ebx ; Push the handle of the file to be closed call fclose ; Closes the file whose handle is on the stack ret ; Go home char *fgets(char *s, int size, FILE *stream); int fclose(FILE *stream);
textFile.asm 4/5 memhelp: mov eax,1 call newline mov ebx, dword helpmsg ; Load address of help text into eax .chkln: cmp dword [ebx],0 ; Does help msg pointer point to a null? jne .show ; If not, show the help lines mov eax,1 ; Load eax with number of newslines to output call newline ; Output the newlines ret .show: push ebx ; Push address of help line on the stack call printf ; Display the line add esp,4 add ebx,HELPSIZE ; Increment address by length of help line jmp .chkln ; Loop back and check to see if we done yet
textFile.asm 5/5 [SECTION .data] ; Section containing initialised data diskhelpnm db 'helptextfile.txt',0 opencode db 'r',0 helpmsg db 'TEXTTEST: Generates a test file. Arg(1) should be the # of ',10,0 HELPSIZE EQU $-helpmsg db 'lines to write to the file. All other args are concatenated',10,0 db 'into a single line and written to the file. If no text args',10,0 db 'are entered, random text is written to the file. This msg ',10,0 db 'appears only if the file HELPTEXTFILE.TXT cannot be opened. ',10,0 helpend dd 0 [SECTION .bss] ; Section containing uninitialized data HELPLEN EQU 72 ; Define length of a line of help text data helpline resb HELPLEN ; Reserve space for disk-based help text line
linlib.asm extern printf [SECTION .text] newline: mov ecx,10 ; We need a skip value, which is 10 minus the sub ecx,eax ; number of newlines the caller wants. add ecx, dword nl ; This skip value is added to the address of push dword ecx ; the newline buffer nl before calling printf. call printf ; Display the selected number of newlines add esp,4 ; Clean up the stack ret ; Go home nl db 10,10,10,10,10,10,10,10,10,10,0
Makefile ASM = nasm –f elf CC = gcc –o all: textFile textFile: textFile.o linlib.o $(CC) textFile $+ textFile.o: textFile.asm $(ASM) textFile.asm linlib.o: linlib.asm $(ASM) linlib.asm
Tiny Search Engine ( assembly course project)design doc *小组成员: 支流(00108103)、席倩(00108091)、杨志丰(00108094)…… * 功能描述: 读取包含至少100个URL的文件…… * 包内文件介绍 * 使用方法: * 功能模块: * 程序特点: * Bug及拟改进之处: *实习体会:
Thank you for your attention!