Assembly 汇编语言帮助查找agrv[1][0]
我试图获取x86汇编语言中存储在Assembly 汇编语言帮助查找agrv[1][0],assembly,x86,nasm,argv,Assembly,X86,Nasm,Argv,我试图获取x86汇编语言中存储在argv[1]中的第一个元素。 最初我将堆栈弹出两次到eax,因为我想要argc,这样我可以计算argc的数量。然后弹出argv到ebx。我想把[ebx]放到bl里。从这里我迷路了。我在组装方面几乎没有经验,我只是想了解它 main: ; mov ecx, 0 ;count output characters pop eax ;reject this 32 bits pop eax ;get argc ; pop ebx ;
argv[1]
中的第一个元素。
最初我将堆栈弹出两次到eax
,因为我想要argc
,这样我可以计算argc
的数量。然后弹出argv
到ebx
。我想把[ebx]
放到bl
里。从这里我迷路了。我在组装方面几乎没有经验,我只是想了解它
main:
;
mov ecx, 0 ;count output characters
pop eax ;reject this 32 bits
pop eax ;get argc
;
pop ebx ; get argv
;mov bl, [ebx]
;
add al, 30H ;convert integer to ascii
mov edi, cline ;put char in output buffer
mov byte [edi],al
;inc edi
;mov [edi], bl
inc ecx ;increment output char count
inc edi ;increment pointer to o/p buffer
mov al, 0aH ;LF to end line
mov byte[edi],al ;put it at end of output line
inc ecx ;increment output char count
push ecx ;save char count on stack
mov edx,len ;length of string to write
mov ecx,msg ;addr of string
mov ebx,1 ;file descriptor 1 = stdout
mov eax,4 ;"write" system call
int 0x80 ;call the kernel
;
pop edx ;restore char count into edx for system call
mov ecx,cline ;address of string
mov ebx,1 ;file descriptor 1 = stdout
我有三项建议:
tmp$ ./a.out test
tmp$ echo $?
116
tmp$
检查生成的程序集,我发现它不使用pops,而只是根据堆栈参数相对于基指针ebp的位置加载寄存器。我发现我喜欢将mov与基指针一起使用的这种风格
我没有像您尝试的那样使用pop,因此其他人可能会评论如何使用pop
我已经对程序集做了一些注释,对我认为正在发生的事情进行了注释。欢迎更正
tmp$ cat main.s
.file "main.c"
.text
.globl main
.type main,@function
main:
pushl %ebp ; push the callers base pointer onto the stack
movl %esp, %ebp ; save esp into the base pointer
subl $8, %esp ; make some room on the stack for main ...
andl $-16, %esp ; but pad to an aligned stack pointer
movl $0, %eax
subl %eax, %esp ; dunno why gcc subtracts 0 from stack pointer
cmpl $1, 8(%ebp) ; compare 1 and argc, which is 8 past the base pointer
jle .L2 ; jump to .L2 if argc <= 1
movl 12(%ebp), %eax ; fetch argv into eax
addl $4, %eax ; skip the first 32 bits at that address
movl (%eax), %eax ; fetch address from the resulting address
movsbl (%eax),%eax ; load byte from that address into eax
movl %eax, -4(%ebp) ; put that byte onto the stack (see note 1.)
jmp .L1
.L2:
movl $0, -4(%ebp)
.L1:
movl -4(%ebp), %eax ; load return value from stack (see note 1.)
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2"
tmp$
tmp$cat main.s
.file“main.c”
.文本
格洛博梅因酒店
.type main,@函数
主要内容:
pushl%ebp;将调用者基指针推送到堆栈上
移动百分比esp,%ebp;将esp保存到基指针中
低于8美元,特别是;在堆栈上留出一些空间用于主。。。
andl$-16%,esp;但将pad移到对齐的堆栈指针
movl$0,%eax
次级%eax,%esp;不知道为什么gcc会从堆栈指针中减去0
cmpl$1,8%(ebp);比较1和argc,argc超过基指针8
jle.L2;如果argc我有三个建议,请跳到.L2:
如果你还没有
尽量减少试图解决眼前问题的代码,以及
如果可能的话,在卡住时检查C编译器生成的程序集
为了获取argv,我可以简单地从程序返回argv[1]中第一个字符的ASCII码,以避免系统调用。系统调用与获取argv是不同的问题,因此避免系统调用会将注意力集中在手头的问题上
然后我可以编译一个最小的C程序并检查生成的程序集。如果你记得当你去新泽西州的AT&T时,目的地在美国的右边,那么阅读AT&T语法汇编并没有那么糟糕
程序只返回argv[1]中第一个字符的ASCII码。t是116
tmp$ ./a.out test
tmp$ echo $?
116
tmp$
检查生成的程序集,我发现它不使用pops,而只是根据堆栈参数相对于基指针ebp的位置加载寄存器。我发现我喜欢将mov与基指针一起使用的这种风格
我没有像您尝试的那样使用pop,因此其他人可能会评论如何使用pop
我已经对程序集做了一些注释,对我认为正在发生的事情进行了注释。欢迎更正
tmp$ cat main.s
.file "main.c"
.text
.globl main
.type main,@function
main:
pushl %ebp ; push the callers base pointer onto the stack
movl %esp, %ebp ; save esp into the base pointer
subl $8, %esp ; make some room on the stack for main ...
andl $-16, %esp ; but pad to an aligned stack pointer
movl $0, %eax
subl %eax, %esp ; dunno why gcc subtracts 0 from stack pointer
cmpl $1, 8(%ebp) ; compare 1 and argc, which is 8 past the base pointer
jle .L2 ; jump to .L2 if argc <= 1
movl 12(%ebp), %eax ; fetch argv into eax
addl $4, %eax ; skip the first 32 bits at that address
movl (%eax), %eax ; fetch address from the resulting address
movsbl (%eax),%eax ; load byte from that address into eax
movl %eax, -4(%ebp) ; put that byte onto the stack (see note 1.)
jmp .L1
.L2:
movl $0, -4(%ebp)
.L1:
movl -4(%ebp), %eax ; load return value from stack (see note 1.)
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2"
tmp$
tmp$cat main.s
.file“main.c”
.文本
格洛博梅因酒店
.type main,@函数
主要内容:
pushl%ebp;将调用者基指针推送到堆栈上
移动百分比esp,%ebp;将esp保存到基指针中
低于8美元,特别是;在堆栈上留出一些空间用于主。。。
andl$-16%,esp;但将pad移到对齐的堆栈指针
movl$0,%eax
次级%eax,%esp;不知道为什么gcc会从堆栈指针中减去0
cmpl$1,8%(ebp);比较1和argc,argc超过基指针8
jle.L2;如果argc请跳转到.L2,请查看此处:
以下是它的工作原理:
argc = [esp]
argv = [esp + 4 * ARG_NUMBER]
其中ARG_NUMBER是argv中基于1的索引
./test hello there
[esp] = 3
[esp + 4 * 1] = ./test (program path and name)
[esp + 4 * 2] = hello
[esp + 4 * 3] = there
我将使用C库中的printf使其更清晰:
extern printf, exit
section .data
fmtint db "%d", 10, 0
fmtstr db "%s", 10, 0
section .text
global main
main:
push dword[esp]
push fmtint
call printf ; print argc
add esp, 4 * 2
mov ebx, 1
PrintArgV:
push dword [esp + 4 * ebx]
push fmtstr
call printf ; print each param in argv
add esp, 4 * 2
inc ebx
cmp ebx, dword [esp]
jng PrintArgV
call exit
为了保持简单,这里没有错误检查。您可以检查arg的数量是否超过预期值或其他值
@Ed Cashin,如果OP正在学习INTEL语法,为什么要将其与AT&T混淆?看看这里:
以下是它的工作原理:
argc = [esp]
argv = [esp + 4 * ARG_NUMBER]
其中ARG_NUMBER是argv中基于1的索引
./test hello there
[esp] = 3
[esp + 4 * 1] = ./test (program path and name)
[esp + 4 * 2] = hello
[esp + 4 * 3] = there
我将使用C库中的printf使其更清晰:
extern printf, exit
section .data
fmtint db "%d", 10, 0
fmtstr db "%s", 10, 0
section .text
global main
main:
push dword[esp]
push fmtint
call printf ; print argc
add esp, 4 * 2
mov ebx, 1
PrintArgV:
push dword [esp + 4 * ebx]
push fmtstr
call printf ; print each param in argv
add esp, 4 * 2
inc ebx
cmp ebx, dword [esp]
jng PrintArgV
call exit
为了保持简单,这里没有错误检查。您可以检查arg的数量是否超过预期值或其他值
@Ed Cashin,如果OP正在学习英特尔语法,为什么要将其与AT&T混淆?请不要忘记使用代码块。我帮你修好了。请别忘了使用代码块。“我帮你修好了。”Gunner问我为什么在OP明显使用Intel语法的情况下使用AT&T语法。原因是,我相信达到双语熟练程度要比完全避免AT&T语法困难得多。检查“-save temps”留下的输出的能力弥补了任何暂时的混乱。为了进一步缓解这种不适,我提供了一个助记符。谢谢你的提问。@Gunner问我为什么在OP明显使用Intel语法的情况下使用AT&T语法。原因是,我相信达到双语熟练程度要比完全避免AT&T语法困难得多。检查“-save temps”留下的输出的能力弥补了任何暂时的混乱。缓和