这个程序出自《Assembly Language step by step programming with linux》第11章,用于显示程序的命令行参数,首先看代码:
SECTION .data ; Section containing initialised data
ErrMsg db "Terminated with error.",10
ERRLEN equ $-ErrMsg
SECTION .bss ; Section containing uninitialized data
; This program handles up to MAXARGS command-line arguments. Change the
; value of MAXARGS if you need to handle more arguments than the default 10.
; In essence we store pointers to the arguments in a 0-based array, with the
; first arg pointer at array element 0, the second at array element 1, etc.
; Ditto the arg lengths. Access the args and their lengths this way:
; Arg strings: [ArgPtrs + <index reg>*4]
; Arg string lengths: [ArgLens + <index reg>*4]
; Note that when the argument lengths are calculated, an EOL char (10h) is
; stored into each string where the terminating null was originally. This
; makes it easy to print out an argument using sys_write. This is not
; essential, and if you prefer to retain the 0-termination in the arguments,
; you can comment out those lines as indicated.
MAXARGS equ 10 ; Maximum # of args we support
ArgCount: resd 1 ; # of arguments passed to program
ArgPtrs: resd MAXARGS ; Table of pointers to arguments
ArgLens: resd MAXARGS ; Table of argument lengths
SECTION .text ; Section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy...
; Get the command line argument count off the stack and validate it:
pop ecx ; TOS contains the argument count
cmp ecx,MAXARGS ; See if the arg count exceeds MAXARGS
ja Error ; If so, exit with an error message
mov dword [ArgCount],ecx ; Save arg count in memory variable
; Once we know how many args we have, a loop will pop them into ArgPtrs:
xor edx,edx ; Zero a loop counter
SaveArgs:
pop dword [ArgPtrs + edx*4] ; Pop an arg into the memory table
inc edx ; Bump the counter to the next argument
cmp edx,ecx ; Is the counter = the argumemt count?
jb SaveArgs ; If not, loop back and do another
; With the argument pointers stored in ArgPtrs, we calculate their lengths:
xor eax,eax ; Searching for 0, so clear AL to 0
xor ebx,ebx ; Pointer table offset starts at 0
ScanOne:
mov ecx,0000ffffh ; Limit search to 65535 bytes max
mov edi,dword [ArgPtrs+ebx*4] ; Put address of string to search in EDI
mov edx,edi ; Copy starting address into EDX
cld ; Set search direction to up-memory
repne scasb ; Search for null (0 char) in string at edi
; Comment out the following line if you need mull-terminated arguments:
mov byte [edi-1],10 ; Store an EOL where the null used to be
sub edi,edx ; Subtract position of 0 from start address
mov dword [ArgLens+ebx*4],edi ; Put length of arg into table
inc ebx ; Add 1 to argument counter
cmp ebx,[ArgCount] ; See if arg counter exceeds argument count
jb ScanOne ; If not, loop back and do another one
; Display all arguments to stdout:
xor esi,esi ; Start (for table addressing reasons) at 0
Showem:
mov ecx,[ArgPtrs+esi*4] ; Pass offset of the message
mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 1: Standard Output
mov edx,[ArgLens+esi*4] ; Pass the length of the message
int 80H ; Make kernel call
inc esi ; Increment the argument counter
cmp esi,[ArgCount] ; See if we've displayed all the arguments
jb Showem ; If not, loop back and do another
jmp Exit ; We're done! Let's pack it in!
Error: mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 2: Standard Error
mov ecx,ErrMsg ; Pass offset of the error message
mov edx,ERRLEN ; Pass the length of the message
int 80H ; Make kernel call
Exit: mov eax,1 ; Code for Exit Syscall
mov ebx,0 ; Return a code of zero
int 80H ; Make kernel call
程序分析:
pop ecx //栈顶是命令行参数的个数
cmp ecx,MAXARGS //比较参数的个数与最大参数个数(10)
ja Error //如果大于最大参数个数,则跳转到Error
mov dword [ArgCount],ecx //保存参数个数值到ArgCount变量中
xor edx,edx //edx清零,用于循环计数
SaveArgs:
pop dword [ArgPtrs + edx*4] //保存命令行参数字符串地址ArgPtrs数组
inc edx //edx=edx+1
cmp edx,ecx //比较edx和命令行参数个数
jb SaveArgs //如果edx<ecx,跳转到SaveArgs,继续循环。
xor eax,eax //eax清零,因此al=0
xor ebx,ebx //ebx清零,用于循环计数
ScanOne:
mov ecx,0000ffffh //ecx=65535,限制最大扫描次数
mov edi,dword [ArgPtrs+ebx*4] //edi= &ArgPtrs[ebx*4]
mov edx,edi //edx=edi
cld //清除DF标志,控制扫描字符串从地地址到高地址
repne scasb //扫描edi中保存的字符串,到0字符扫描结束。
mov byte [edi-1],10 //把0字符替换成10(换行符)
sub edi,edx //edi=edi-edx,得到字符串长度(包括换行符)
mov dword [ArgLens+ebx*4],edi //把长度值保存到ArgLens数组中
inc ebx //ebx=ebx+1
cmp ebx,[ArgCount] //比较ebx与ArgCount变量值
jb ScanOne //如果循环计数小于参数个数,跳转ScanOne,继续循环
xor esi,esi //esi清零
Showem:
mov ecx,[ArgPtrs+esi*4] //ecx=字符串地址
mov eax,4 //系统调用sys_write号
mov ebx,1 //写到标准输出
mov edx,[ArgLens+esi*4] //字符串长度
int 80H //执行系统调用
inc esi //esi=esi+1
cmp esi,[ArgCount] //比较esi和命令行参数个数
jb Showem //如果esi小于命令行参数个数,继续循环
jmp Exit
makefie文件内容:
showargs1: showargs1.o
ld -o showargs1 showargs1.o
showargs1.o: showargs1.asm
nasm -f elf -g -F stabs showargs1.asm -l showargs1.lst
测试:
[root@bogon showargs1]# make
nasm -f elf -g -F stabs showargs1.asm -l showargs1.lst
ld -o showargs1 showargs1.o
[root@bogon showargs1]# ./showargs1
./showargs1
[root@bogon showargs1]# ./showargs1 p1 p2 p3
./showargs1
p1
p2
p3