x86 程序集,误导性错误
我正在尝试学习汇编,并有一个 AT&T 语法的程序,可与 GNU AS 一起使用,我相信它应该可以工作。 我在 GDB 中收到此错误:
Program received signal SIGSEGV, Segmentation fault.
.PROGRAM () at concatenator.s:60
60 call strlen
Current language: auto; currently asm
代码是:
.file "concatenator.s"
.globl _start
.section .text
strlen:
mov %esp, (str1)
push %ebx
push %ecx
push %edx
mov $1, %edi
sub %ecx, %ecx
sub %al, %al
not %ecx
cld
repne scasb
not %ecx
dec %ecx
mov %ecx, %eax
pop %edx
pop %ecx
pop %ebx
leave
ret
write:
push %eax
push %ebx
push %ecx
push %edx
mov %eax, %ecx
mov $4, %eax
mov $4, %edx
mov $2, %ebx
int $0x80
pop %edx
pop %ecx
pop %ebx
pop %eax
ret
.globl concatenate
concatenate:
pop %eax
mov %eax, (str2)
pop %eax
mov %eax, (str1)
push %ebx
push %ecx
push %edx
pushl %ebp#Pushes Previous programs local vars to the stack.
movl %esp, %ebp
subl $24, %esp
.PROGRAM:
movl (str1), %esp#Moves str1 to ESP
call strlen#//Strlen counts len of ESP
movl %eax, -16(%ebp)#//Moves eax[Return] into ebp[-16](len)
movl $str2, (%esp)#//Moves str2 to ESP
call strlen#//Counts len of ESP
subl $1, %eax#//Removes one from the return value
movl %eax, -12(%ebp)#//Stores return in INT len2
//movl -12(%ebp), %eax
movl %eax, -8(%ebp)#//Stores return in INT J
movl $0, -4(%ebp)##//INT X = 0
jmp .L7
.L8:
addl $1, -8(%ebp)#//ADDS 1 to J
movl -8(%ebp), %eax#//Moves J to EAX
movl -4(%ebp), %edx#//MOVES X TO EDX
movzbl str1(%edx), %edx#//Moves str1[EDX] (EDX is X) to EDX and fills wit null
movb %dl, str2(%eax)#//Moves one byte, (Tbhe character we just copied) into str2 [EAX]
addl $1, -4(%ebp)#//INT X++
.L7:
movl -4(%ebp), %eax#//Moves INT X to EAX
cmpl -16(%ebp), %eax#//Compares len with EAX
jl .L8#//While below length of string one, go to L8 and copy str1 to str2
addl $1, -8(%ebp)#//Adds one to J(J++)
movl -8(%ebp), %eax#//Moves J to EAX
movb $0, str2(%eax)#//Adds null character to string at position J.
.RETURN:
leave
pop %edx
pop %ecx
pop %ebx
mov (str2), %eax
ret
_start:
push str1
push str2
call concatenate
mov %eax, str2
mov $1, %eax
mov $0, %ebx
int $0x80
.globl str1
.section .data
str1:
.string "DEF"
.zero 252
str2:
.string "ABC"
.zero 252
我确实明显做错了什么吗?以及您会推荐哪些资源来学习汇编? (我已阅读 WikiBooks X86 组装文章,以及大部分 GAS 手册)。
I am trying to learn assembly, and have a program in AT&T syntax, for use with GNU AS Which I believe should work.
I receive this error with GDB:
Program received signal SIGSEGV, Segmentation fault.
.PROGRAM () at concatenator.s:60
60 call strlen
Current language: auto; currently asm
The code is:
.file "concatenator.s"
.globl _start
.section .text
strlen:
mov %esp, (str1)
push %ebx
push %ecx
push %edx
mov $1, %edi
sub %ecx, %ecx
sub %al, %al
not %ecx
cld
repne scasb
not %ecx
dec %ecx
mov %ecx, %eax
pop %edx
pop %ecx
pop %ebx
leave
ret
write:
push %eax
push %ebx
push %ecx
push %edx
mov %eax, %ecx
mov $4, %eax
mov $4, %edx
mov $2, %ebx
int $0x80
pop %edx
pop %ecx
pop %ebx
pop %eax
ret
.globl concatenate
concatenate:
pop %eax
mov %eax, (str2)
pop %eax
mov %eax, (str1)
push %ebx
push %ecx
push %edx
pushl %ebp#Pushes Previous programs local vars to the stack.
movl %esp, %ebp
subl $24, %esp
.PROGRAM:
movl (str1), %esp#Moves str1 to ESP
call strlen#//Strlen counts len of ESP
movl %eax, -16(%ebp)#//Moves eax[Return] into ebp[-16](len)
movl $str2, (%esp)#//Moves str2 to ESP
call strlen#//Counts len of ESP
subl $1, %eax#//Removes one from the return value
movl %eax, -12(%ebp)#//Stores return in INT len2
//movl -12(%ebp), %eax
movl %eax, -8(%ebp)#//Stores return in INT J
movl $0, -4(%ebp)##//INT X = 0
jmp .L7
.L8:
addl $1, -8(%ebp)#//ADDS 1 to J
movl -8(%ebp), %eax#//Moves J to EAX
movl -4(%ebp), %edx#//MOVES X TO EDX
movzbl str1(%edx), %edx#//Moves str1[EDX] (EDX is X) to EDX and fills wit null
movb %dl, str2(%eax)#//Moves one byte, (Tbhe character we just copied) into str2 [EAX]
addl $1, -4(%ebp)#//INT X++
.L7:
movl -4(%ebp), %eax#//Moves INT X to EAX
cmpl -16(%ebp), %eax#//Compares len with EAX
jl .L8#//While below length of string one, go to L8 and copy str1 to str2
addl $1, -8(%ebp)#//Adds one to J(J++)
movl -8(%ebp), %eax#//Moves J to EAX
movb $0, str2(%eax)#//Adds null character to string at position J.
.RETURN:
leave
pop %edx
pop %ecx
pop %ebx
mov (str2), %eax
ret
_start:
push str1
push str2
call concatenate
mov %eax, str2
mov $1, %eax
mov $0, %ebx
int $0x80
.globl str1
.section .data
str1:
.string "DEF"
.zero 252
str2:
.string "ABC"
.zero 252
Is there anything I really obviously did wrong?, and which resources would you recommend for learning assembly? (I have read the WikiBooks X86 Assembly Article, and Most of the GAS Manual).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这:
可能是导致您崩溃的直接原因。我从未使用过在 %esp; 中传递参数的 x86 系统。一般来说,%esp 必须始终保持有效的堆栈指针。在许多系统上,它还必须在调用指令时满足一些对齐保证。
我假设您打算将 str1 的内存内容移动到 %esp 指向的内存位置,但这不是它的作用。您应该能够通过在调试器中逐条指令地单步执行程序来看到这一点。这是编写汇编语言时需要学习的一项重要技能,并将帮助您自己发现此类问题。
This:
is likely the immediate cause of your crash. I've never worked with a x86 system on which an argument was passed in %esp; generally speaking, %esp must remain a valid stack pointer at all times. On many systems, it must additionally meet some alignment guarantee at the time of a call instruction.
I assume that you intend to move the memory contents of str1 to the memory location pointed to by %esp, but that's not what this does. You should be able to see that by stepping through the program execution in the debugger instruction-by-instruction. This is an important skill to learn for writing assembly, and will help you find issues like this on your own.
除了stephentyrone的答案之外,我建议您编译一个使用 gcc -S 调用 strlen 的 C 程序,并观察生成的 .s 文件,以了解系统上正确的调用约定(正如他所说,将值传递给< /em> %esp 不是。我本来希望在 %eax 中传递一个参数,但已经有一段时间了,而且我一直在使用 amd64 ABI,所以我可能会感到困惑)。
In addition to stephentyrone's answer, I suggest that you compile a C program that calls strlen with gcc -S and observe the generated .s file for the proper calling convention on your system (and as he said, passing the value in %esp is not it. I would have expected a single argument to be passed in %eax but it's been some time and I have been using the amd64 ABI meanwhile so I may be confused).
将参数传递给子例程的一种相当正常、安全的方法是将参数值压入堆栈。
稍微快一点的方法是将参数值移动到寄存器中:但不是像斯蒂芬所说的那样,移动到 esp 寄存器中(push、pop、call 和 ret 操作码假设 esp 包含指向堆栈的指针)。
A fairly normal, safe way to pass a parameter to a subroutine is to push the parameter value onto the stack.
A slightly quicker way is to move the the parameter value into a register: but not, as stephen says, the esp register (the push, pop, call, and ret opcodes assume that esp contains a pointer to the stack).