2016-03-10 6 views
1

У меня есть кусок кода в файле с именем 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 скомпилировать, и я использую GCC на Ubuntu14.04 для компиляции Этот код:

gcc -o demo cpuid.s 

И он скомпилирован успешно. Затем я запускаю демо на терминале, но он запрашивает 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. 

Просьба указать, в чем проблема и как ее решить. Благодарю.

+1

Добавить -m32 в вашу командную строку gcc. –

+0

@Paul Griffiths Итак, как его решить? – leohotfn

+0

'.code32' неверен! Вы не можете запустить 32-разрядный код в 64-битном режиме. Вы можете заставить ассемблер генерировать 32-битную сборку с '.code32', но это не запустило ее. Как уже сказал Джонатан Рейнхарт, вам нужно собрать файл в виде 32-битного исходного файла для этого. – fuz

ответ

2

В 64-разрядном (amd64) процессе может работать только 64-разрядный код. Директива .code32 заставляет ассемблер собирать ваши инструкции в виде 32-битного кода, но это не делает это волшебным образом. Вместо этого процессор, все еще находящийся в режиме 64 бит, интерпретирует ваш 32-разрядный машинный код как 64-битный машинный код с типично катастрофическими результатами.

Если вы хотите написать 32-битную сборку, вам необходимо скомпилировать всю программу в виде 32-разрядной программы. Это приводит к тому, что Linux устанавливает для процессора 32-битный режим совместимости для вашей программы, так что 32-разрядный код работает нормально. С помощью gcc это можно сделать, передав -m32 компилятору на всех этапах компиляции. В текущем примере, просто удалите .code32 директиву, а затем компилировать с

gcc -m32 -o demo test.s 
+0

Спасибо, FUZxxl. Я решаю, как с вашей помощью записать 32-битную сборку в режиме 64 бит. Но если я изменил свой код с 32-битного режима на 64-битный режим, у меня возникла другая проблема, детали отображаются в вопросе, который был изменен только сейчас. – leohotfn

+0

@leohotfn Вы не можете просто изменить 'esp' на' rsp' и ожидать, что код будет работать в режиме 64 бит. Многие детали различны, например, соглашение о вызове. – fuz

+0

ОК, спасибо очень много. :-) – leohotfn

1

Ключевым моментом забрать здесь это:

«разрядность» ваш исполняемый файл (ELF) и «битность» машинного кода GAS испускает независимый.

Как упоминалось в FUZxxl, .code32 сообщает GAS, чтобы испустить 32-разрядный машинный код. Тем не менее, GCC (вождение GAS) в конечном счете производит 64-разрядный файл ELF.

Когда вы запускаете эту программу, ядро ​​говорит: «Это 64-разрядный ELF, я запустил его в 64-разрядном режиме». Это, конечно, не очень хорошо, когда CPU (в 64-битном режиме) пытается выполнить ваши 32-битные инструкции.

Добавление -m32 (как указано в комментариях) говорит GCC, чтобы сделать две вещи:

  • Производят 32-битный ELF файл
  • Link против 32-битных libc
  • Включать 32-битную C код запуска
Смежные вопросы