在 asm 中编写和调试 min 程序

Writing and debugging a min program in asm

我正在尝试编写一个程序来查找 asm 中整数列表的最小值。这是我目前所拥有的:

.section .data

data_items:
    .long 2,3,4,5,1,9,10            # set 10 as the sentinal value

.section text

.globl _start
_start:

    # %ebx holds min
    # %edi holds index (destination index)
    # %eax current data item

    movl 5, %ebx                 # set the current min to 255 
    movl [=10=], %edi                   # the index is also zero
    

start_loop:

    movl data_items(,%edi,4), %eax  # set %eax equal to the current data item
    cmpl , %eax                  # compare %eax with zero to see if we should exit 
    je exit_loop                    # if it's the sentinel value, exit
    incl %edi                       # increment the index
    cmpl %eax, %edi                 # compare the current value to the current min
    jge start_loop                  # if it's not less than the current value, go to start
    movl %eax, %ebx                 # move the current value if less that the current min
    jmp start_loop                  # always go back to the start if we've gotten this far  

exit_loop:
    movl , %eax                   # push the linux system call to %eax (1=exit)
    int [=10=]x80                       # give linux control (so it will exit)      

当我 运行 这样做时,我得到以下信息:

$ as min.s -o min.o && ld min.o -o min && ./min

Segmentation fault (core dumped)

应该如何调试 asm?例如,至少在 C 中,编译器会告诉您错误可能是什么以及行号,而在这里我几乎一无所知。 (注意:错误是 .section text 而不是 .section .text,但如何计算呢?)

很可能在 C 中编写的程序编译时没有警告但崩溃了(例如 NULL 指针 deref),你会看到完全相同的东西。不过在 asm 中更有可能。

您使用调试器(例如 GDB)调试 asm。请参阅 https://whosebug.com/tags/x86/info 底部的提示。如果您进行任何系统调用,请使用 strace 查看您的程序实际在做什么。

要对其进行调试,您会在 GDB 下 运行 它并注意到它在第一条指令 movl 5, %ebx 上出现了段错误。它不访问内存,因此代码获取一定有故障。因此,您的部分一定有问题,导致您部分中的代码链接到可执行文件的不可执行部分。

objdump -d 也会给你一个提示:它默认反汇编 .text 部分,而这个程序没有。


text 而不是 .text 导致此问题的原因是,具有随机名称的节(不是少数特别识别的节之一)的默认设置是不带 exec 的读+写。

在 GAS 中,使用 .text.data.section .text 或 .data 的特殊快捷方式指令可以避免这些部分出现此问题. https://sourceware.org/binutils/docs/as/Text.html

但并非所有 "standard" 部分都有特殊指令,您仍然需要 .section .rodata 切换到只读数据部分,您 应该 已经把你的阵列。 (读,不写。在较新的工具链上,也没有 exec)。不过,您可以使用 .comm.lcomm (https://sourceware.org/binutils/docs/as/bss.html)

而不是切换到 .bss 部分

另一个可能的问题是您正在将此 32 位代码构建为 64 位可执行文件(除非您使用的是仅 32 位的安装,其中 as --32 是默认设置)。使用 32 位寻址模式在 64 位模式下工作,t运行cating 地址为 32 位。这在 Linux 上访问位置相关可执行文件中的静态数据时有效,因为所有代码+数据都链接到虚拟地址 space.

的低 2GiB

但是任何对 (%esp)-4(%ebp) 或其他任何内容的访问都会出错,因为 64 位进程中的堆栈被映射到一个高地址,在低 32 位之外具有非零位。

你会注意到 GDB 中的这个问题,因为 layout reg 会显示所有 16 个 64 位整数寄存器,RAX..R15.