与前面的版本不同,这个是使用libc库版本的显示命令行参数程序,因为main函数并不是程序的入口点,而是由libc库的代码调用,所以命令行参数在栈上的位置有不同,先看示例程序:
[SECTION .data] ; Section containing initialised data
ArgMsg db "Argument %d: %s",10,0
[SECTION .bss] ; Section containing uninitialized data
[SECTION .text] ; Section containing code
global main ; Required so linker can find entry point
extern printf ; Notify linker that we're calling printf
main:
push ebp ; Set up stack frame for debugger
mov ebp,esp
push ebx ; Program must preserve ebp, ebx, esi, & edi
push esi
push edi
;;; Everything before this is boilerplate; use it for all ordinary apps!
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 addr. of an argument on the stack
push esi ; Push argument number
push ArgMsg ; Push address of display string
call printf ; Display the argument # and argument
add esp,12 ; Stack cleanup: 3 parms x 4 bytes = 12
inc esi ; Bump argument # to next argument
dec edi ; Decrement argument counter by 1
jnz .showit ; If argument count is 0, we're done
;;; Everything after this is boilerplate; use it for all ordinary apps!
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp,ebp ; Destroy stack frame before returning
pop ebp
ret ; Return control to Linux
程序分析:
main:
push ebp //保存旧的ebp
mov ebp,esp //ebp = esp,保存栈指针到ebp
push ebx //保存ebx
push esi //保存esi
push edi //保存edi
mov edi,[ebp+8] //ebp+4保存的是调用main函数后的返回地址,ebp+8,是main函数左边的第一个参数:argc,即命令行参数个数
mov ebx,[ebp+12] //ebp+12保存的是argv,就是命令行参数字符串指针数组。
xor esi,esi //esi=0
.showit:
push dword [ebx+esi*4] //把字符串参数压入堆栈
push esi //压入参数编号(索引值)
push ArgMsg //格式化字符串
call printf //调用printf,显示这个字符串参数信息
add esp,12 //清理栈
inc esi //esi=esi+1,下一个参数
dec edi //edi=edi-1,用于控制循环次数
jnz .showit //如果edi不等于0,则继续循环,否则结束。循环次数是命令行参数个数。
pop edi //恢复edi寄存器
pop esi //恢复esi寄存器
pop ebx //恢复ebx寄存器
mov esp,ebp //esp=ebp,恢复函数调用开始时栈指针位置
pop ebp //恢复ebp
ret
测试:
[root@bogon showargs3]# make
nasm -f elf -g -F stabs showargs3.asm
gcc showargs3.o -o showargs3
[root@bogon showargs3]# ./showargs3 p1 p2 p3 p4 p5
Argument 0: ./showargs3
Argument 1: p1
Argument 2: p2
Argument 3: p3
Argument 4: p4
Argument 5: p5