x86 程序集,误导性错误

发布于 2024-08-04 19:30:29 字数 2710 浏览 9 评论 0原文

我正在尝试学习汇编,并有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

偏爱自由 2024-08-11 19:30:29

这:

movl    (str1), %esp

可能是导致您崩溃的直接原因。我从未使用过在 %esp; 中传递参数的 x86 系统。一般来说,%esp 必须始终保持有效的堆栈指针。在许多系统上,它还必须在调用指令时满足一些对齐保证。

我假设您打算将 str1 的内存内容移动到 %esp 指向的内存位置,但这不是它的作用。您应该能够通过在调试器中逐条指令地单步执行程序来看到这一点。这是编写汇编语言时需要学习的一项重要技能,并将帮助您自己发现此类问题。

This:

movl    (str1), %esp

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.

与往事干杯 2024-08-11 19:30:29

除了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).

岁月苍老的讽刺 2024-08-11 19:30:29

将参数传递给子例程的一种相当正常、安全的方法是将参数值压入堆栈。

稍微快一点的方法是将参数值移动到寄存器中:但不是像斯蒂芬所说的那样,移动到 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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文