为什么这个装配程序不能运行?

时间:2016-03-10 11:22:48

标签: c linux assembly

我在一个名为 cpuid.s 的文件中有一段代码:

.code32
.section .data
output:
    .asciz "The processor Vendor ID is '%s'\n"
.section .bss
    .lcomm buffer, 12
.section .text
.globl main
main:
    movl $0, %eax
    cpuid
    movl $buffer, %edi
    movl %ebx, (%edi)
    movl %edx, 4(%edi)
    movl %ecx, 8(%edi)
    pushl $buffer
    pushl $output
    call printf
    addl $8, %esp
    pushl $0
    call exit

我的操作系统类型是64位,所以我添加.code32进行编译,我在Ubuntu14.04上使用gcc来编译这段代码:

gcc -o demo cpuid.s

它已成功编译。然后我在终端上运行demo,但它会提示Segmentation fault (core dumped)

所以我用gdb来调试。然后gdb提示:

Program received signal SIGSEGV, Segmentation fault.
__printf (format=0x601078 <buffer> "GenuineIntel") at printf.c:28
28  printf.c: No such file or directory.

请指出我的问题是什么以及如何解决。感谢。

2 个答案:

答案 0 :(得分:2)

在64位(amd64)进程中,只能运行64位代码。 .code32指令强制汇编程序将指令汇编为32位代码,但它并没有使它神奇地起作用。相反,处理器仍然处于64位模式,将您的32位机器代码解释为64位机器代码,通常会带来灾难性后果。

如果要编写32位汇编,则需要将整个程序编译为32位程序。这会导致Linux将处理器设置为程序的32位兼容模式,因此32位代码运行正常。使用gcc,可以通过在编译的所有阶段将-m32传递给编译器来完成。在当前示例中,只需删除.code32指令,然后使用

进行编译
gcc -m32 -o demo test.s

答案 1 :(得分:1)

这里带走的关键点是:

&#34; bitness&#34;您的可执行文件(ELF)文件和&#34; bitness&#34; GAS发出的机器代码是独立的

正如FUZxxl所提到的,.code32告诉GAS发出32位机器代码。但是,GCC(驱动GAS)最终会生成 64位 ELF文件。

当你执行这个程序时,内核说&#34;这是一个64位的ELF,我将以64位模式运行它。&#34;当CPU(在64位模式下)尝试执行32位指令时,这当然不能很好地结束。

添加-m32(如评论中所述)告诉GCC做两件事:

  • 生成32位ELF文件
  • 与32位libc
  • 相关联
  • 包含32位C启动代码