在 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.
我正在尝试编写一个程序来查找 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.
但是任何对 (%esp)
或 -4(%ebp)
或其他任何内容的访问都会出错,因为 64 位进程中的堆栈被映射到一个高地址,在低 32 位之外具有非零位。
你会注意到 GDB 中的这个问题,因为 layout reg
会显示所有 16 个 64 位整数寄存器,RAX..R15.