1

我正在尝试学习汇编,并有一个 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 手册)。

4

3 回答 3

7

这个:

movl    (str1), %esp

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

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

于 2009-09-13T16:19:53.303 回答
0

除了斯蒂芬蒂龙的回答之外,我建议您编译一个使用 gcc -S 调用 strlen 的 C 程序,并观察生成的 .s 文件以了解系统上的正确调用约定(正如他所说,传递 %esp 中的不是我本来希望在 %eax 中传递一个参数,但已经有一段时间了,我一直在使用 amd64 ABI,所以我可能会感到困惑)。

于 2009-09-13T17:15:39.397 回答
0

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

稍微快一点的方法是将参数值移动到寄存器中:但不是,如 stephen 所说,esp 寄存器(push、pop、call 和 ret 操作码假设 esp 包含指向堆栈的指针)。

于 2009-09-13T17:25:03.513 回答