关于

您所在的位置:网站首页 汇编语言main是什么意思 关于

关于

2024-07-16 01:24:21| 来源: 网络整理| 查看: 265

罗云彬老师的

书中十三章再讲Console下exe程序输入参数的问题引入了两个过程_argc和_argv,书中并没有给出详细解释,在这里总结了下。

这两个过程产生的原因是应为汇编不像C语言调用SDK在EP函数就自动帮助传入参数,大家都知道:

int APIENTRY main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, //这个就是程序的命令行参数 int nCmdShow)

又或者在C语言CUI编程中:

int main(int argc, char **argv) { return 0; }

其中argc就是参数的总数,而argv指向的就是包含每一个参数的指针数组

比如: C:\> nc 192.168.0.155 5750

那么argc就是3,argv分别是nc, 192.168.0.155, 5750

但是在汇编中这个过程不会帮我们做好。需要自己来做。可以自己写一个简单的程序调用GetCommandLine来获取输入的参数:

.386 .model flat, stdcall option casemap :none include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib .data? szBuffer db 1024 dup(?) .data szTitle db 'GetCommandLine Results', 0 .code start: invoke RtlZeroMemory, addr szBuffer, sizeof szBuffer invoke GetCommandLine mov esi, eax invoke MessageBox, NULL, esi, addr szTitle, MB_OK invoke ExitProcess, NULL end start

比如我在控制台输入:

由此可见GetCommandLine函数只帮我们做了传入全部参数的功能而非像argc计入参数总数,argv计入每个参数是什么

而_argc和_argv两个过程就是帮我们做这两个事情的

贴代码:

CHAR_BLANK EQU 20h ;这是空格的Ascii的十六进制形式 CHAR_DELI EQU '"' ;---------------------------------------- _argc proc local @dwArgc ; * @dwArgc这个临时变量用于记录输入参数总数 ;---------------------------------------- pushad ;通用寄存器入栈 mov @dwArgc, 0 ;首先置0 invoke GetCommandLine ;获取命令行,地址在eax中 mov esi, eax cld ;清除方向寄存器 _argc_loop: lodsb ;把命令行字符串的第一个字符载入al中 or al, al ;判断字符串以及到了最后一个字符即0 jz _argc_end ;如果ZF置位即已经到达最后一个字符 cmp al, CHAR_BLANK ;由于刚开始的时候可能有空格先判断空格 jz _argc_loop ;如果是空格那么继续往下载入字符直到碰到不是空格为止 ;----------------------------------------------- ; 到这里代表已经碰到了第一个非空格字符 ; 由于lodsb类似C语言中的i++,先传值后挪地址 ; 所以esi要减1回到前面判断为非空格的字符那里 ;----------------------------------------------- dec esi inc @dwArgc ;是第一个参数了就是那个a.exe _argc_loop1: ;这个循环是处理参数的,直到碰到空格才停 lodsb or al, al ;首先判断该参数是不是最后一个参数即跟了0字符 jz _argc_end cmp al, CHAR_BLANK jz _argc_loop ;碰到空格就停 cmp al, CHAR_DELI jnz _argc_loop1 ;如果碰到了"号 ;--------------------------------------------------- ; 大家都知道cmd下是允许用引号的,比如:cd "File Programs" ; 如果你不加引号那么OS会以为File和Programs是两个参数,或者 ; 你也可以这样cd File" "Programs,只要不要有空格就可以了 ; 所以如果你碰到了"号必然是成双的 ; -------------------------------------------------- @@: ;这部分是为了判断引号中的内容,即引号中有空格不会增加参数数目 lodsb or al, al ;;首先判断该参数是不是最后一个参数即跟了0字符 jz _argc_end cmp al, CHAR_DELI jnz @B ;没碰到了第二个引号所以继续判断引号中内容 jmp _argc_loop1 ;引号结束跳回 _argc_end: popad mov eax, @dwArgc ret _argc endp ;---------------------------------------------- _argv proc, _dwArgv:dword, _lpReturn:ptr byte, _dwSize:dword local @dwArgv, @dwFlag ; _dwArgv: 所要得到的参数的下标 ; _lpReturn: 参数内容的返回地址 ; _dwSize: _lpReturn的大小 ; @dwArgv: 主要为了确定目前参数是不是_dwArgv所指定的那个 ; @dwFlag: 如果是_dwArgv所指定的那个就置位 ;----------------------------------------------- pushad ;保护通用寄存器不用说了 inc _dwArgv ;因为一般下标都是0开始的,这里为了@dwArgv判断方便变为1 mov @dwArgv, 0 ;计数器清除 mov edi, _lpReturn invoke GetCommandLine ;下面和_argv中的如出一辙的代码不解释 mov esi, eax cld _argv_loop: lodsb ;这一段主要是为了清除一开始那些没用的空格键 or al, al jz _argv_end cmp al, CHAR_BLANK jz _argv_loop dec esi ;空格清除完毕,碰到第一个字符 inc @dwArgv ;计数器增加,意味着已经是第@dwArgv个参数了 mov @dwFlag, FALSE ;先把标志清空,这个标志用于判断当前参数是不是dwArgv所指定的那个 mov eax, _dwArgv cmp eax, @dwArgv ;看当前参数是不是所要求的那个 jnz @F mov @dwFlag, TRUE ;如果是的话那就让标志置位 @@: _argv_loop1: lodsb or al, al jz _argv_end cmp al, CHAR_BLANK jz _argv_loop ;碰到空格,说明这个参数结束,跳回 cmp al, CHAR_DELI ;看是否是"号 jz _argv_loop2 ;跳转至下一个标号来处理"号 cmp _dwSize, 1 ;------------------------------------------------------------------ ; 这边需要解释一下,这个_dwSize的含义是_lpReturn缓冲区的大小,如果 ; 当前参数是所要求的那个,那么就开始把这个参数一个字节一个字节的 ; 往缓冲区中填充,并且同时减少_dwSize,这里用cmp _dwSize, 1而不是 ; cmp _dwSize, 0是因为字符串最后一个要留着填充空字符来结束字符串 ;------------------------------------------------------------------- jle @F ;如果已经到了缓冲区能容纳的最大字符数但是还没有结束,那么后面的那些全部作废 ;不继续stosb装如缓冲区 cmp @dwFlag, TRUE jne @F ;如果不是所要求的参数那也不继续装入缓冲区 stosb ;装货 dec _dwSize @@: jmp _argv_loop1 _argv_loop2: lodsb or al, al jz _argv_end cmp al, CHAR_DELI ;看有没有第二个"出现,如果出现了说明引号已经结束 jz _argv_loop1 ;跳回 cmp _dwSize, 1 jle @F cmp @dwFlag, TRUE jne @F stosb dec _dwSize @@: jmp _argv_loop2 _argv_end: xor al, al ;把0字符装入最后一个位置来结束字符串 stosb popad ret _argv endp

到这里这两个过程都已经解释完毕了

接下去就是两个宏了

先贴代码:

reverseArgs MACRO arglist:VARARG LOCAL txt,count txt TEXTEQU count = 0 FOR i, count = count + 1 txt TEXTEQU @CatStr(i,,) ENDM IF count GT 0 txt SUBSTR txt,1,@SizeStr(%txt)-1 ENDIF EXITM txt ENDM _invoke MACRO _Proc,args:VARARG LOCAL count count = 0 % FOR i,< reverseArgs( args ) > count = count + 1 push i ENDM call dword ptr _Proc ENDM

这两个宏函数的意思非常简单我觉得困扰大家的并不是这个宏过程的含义而是里面的一些伪指令可能不知道什么意思。

我去查了Intel汇编程序设计里面结构与宏的部分, 里面也没有关于这些伪指令的解释

我用的是masm32 SDK包,在masm32\\help\\masm.chm这个文档中有详细解释

首先就是那个VARARG

看里面一堆好像很牛逼,实际上只是换了鸟文

VARARG属性允许你传递一个多个参数至宏中,当被调用的时候宏参数会传递一个逗号分隔的值列表(如果没有给予值那就是空格)

实际意思就是本来只能传一个参数,现在能传好多个。

接着是CATSTR:

这个CATSTR有两种用法,一种是宏函数,一种是直接用这个定义一个这样的变量,就像TEXTEQU和EQU伪指令做的一样

这里只解释代码中的宏函数用法

txt TEXTEQU @CatStr(i,,)

首先解释下!号类似于C语言中的转义符所以可以直接看成','号就行了,为何加一个,因为!,是一个字符,但看上去是两个,实际上也是两个,为了让编译器看的懂,用括起来,代表我是一个

%txt的意思是取txt所代表的东西而不是txt本身

这里@CatStr(i, , ),意思实际上就是把i和,还有txt所代表东西黏起来。举个例子%txt =   i = 2 ,那么首先把2和,黏起来后变成2,然后黏到%txt前面就变成了。

接下去是SUBSTR:

这里没使用宏函数,使用了定义的方法

txt SUBSTR txt,1,@SizeStr(%txt)-1

最后那个长度参数是不必要的。如果没有指定长度参数 那返回的是所有字符

这个意思就是把txt定义成txt从第一个字符开始的@SizeStr(%txt) - 1个,也就是从屁股后面减掉一个。原因是上面CATSTR得到的结果是1,2, 但是2后面的那个逗号是不必要的

@SizeStr宏显而易见是类似于strlen()函数,做一下搬运工作:

% for i,< reverseArgs( args ) >

可能这句话也十分困扰大家吧,那个%号是用来干什么的?

%原本是展开操作符,为的是把常量表达式转成文本表示形式或者展开文本宏。

显而易见这里是展开文本宏,如果%作为源代码行的第一个字符, 就指示预处理器展开在该行所发现的所有文本宏和宏函数。

那个宏就是reverseArgs(args)

-----------------------------------END--------------------------------------

总结一下:

这两个宏的目的是首先reverseArgs是为了把通过GetCommandLine收到的参数字符串逆置,比如参数是1,2,3那就变成3,2,1

然后在通过_invoke来调用。至于为什么要逆置原因是每个函数都维护着一个帧栈,而参数都是反向压栈,这样的话在最后call的时候可以按顺序出栈,举一个例子:  

#include int add(int a, int b, int c) { return a + b + c; } void main() { int a = 5, b = 2, c = 1; add(a, b, c); return; }

实际上是(这里手写,可能和OD反编译出来的不用,但就是这个意思):

push ebp mov ebp, esp sub esp, 0Ch mov dword ptr [ebp], 5 mov dword ptr [ebp - 4], 2 mov dword ptr [ebp - 8], 1 push dword ptr [ebp - 8] push dword ptr [ebp - 4] push dword ptr [ebp] call 0040FC30 ;假设add在0040FC30 mov esp, ebp pop ebp retn 0040FC30: push ebp mov ebp, esp xor eax, eax mov eax, [ebp + 8] add eax, [ebp + 12] add eax, [ebp + 16] mov esp, ebp pop ebp retn

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭