我正在尝试学习汇编语言作为一种爱好,我经常使用gcc -S
来生成汇编输出。这非常简单,但我无法编译汇编输出。我只是好奇这是否可以完成。我尝试使用-masm=intel
使用标准汇编输出和intel语法。两者都无法使用nasm
进行编译并与ld
相关联。
因此我想问一下是否可以生成汇编代码,然后可以编译。
更准确地说,我使用了以下C代码。
>> cat csimp.c
int main (void){
int i,j;
for(i=1;i<21;i++)
j= i + 100;
return 0;
}
使用gcc -S -O0 -masm=intel csimp.c
生成的程序集,并尝试使用nasm -f elf64 csimp.s
进行编译并与ld -m elf_x86_64 -s -o test csimp.o
相关联。我从nasm得到的输出读取:
csimp.s:1: error: attempt to define a local label before any non-local labels
csimp.s:1: error: parser: instruction expected
csimp.s:2: error: attempt to define a local label before any non-local labels
csimp.s:2: error: parser: instruction expected
这很可能是由于程序集语法损坏造成的。我希望无需手动更正gcc -S
修改:
我得到了hint,我的问题在另一个问题上得到了解决;不幸的是,在测试了那里描述的方法之后,我无法生成nasm
汇编格式。您可以在下面看到objconv
的输出。
因此,我仍然需要你的帮助。
>>cat csimp.asm
; Disassembly of file: csimp.o
; Sat Jan 30 20:17:39 2016
; Mode: 64 bits
; Syntax: YASM/NASM
; Instruction set: 8086, x64
global main: ; **the ':' should be removed !!!**
SECTION .text ; section number 1, code
main: ; Function begin
push rbp ; 0000 _ 55
mov rbp, rsp ; 0001 _ 48: 89. E5
mov dword [rbp-4H], 1 ; 0004 _ C7. 45, FC, 00000001
jmp ?_002 ; 000B _ EB, 0D
?_001: mov eax, dword [rbp-4H] ; 000D _ 8B. 45, FC
add eax, 100 ; 0010 _ 83. C0, 64
mov dword [rbp-8H], eax ; 0013 _ 89. 45, F8
add dword [rbp-4H], 1 ; 0016 _ 83. 45, FC, 01
?_002: cmp dword [rbp-4H], 20 ; 001A _ 83. 7D, FC, 14
jle ?_001 ; 001E _ 7E, ED
pop rbp ; 0020 _ 5D
ret ; 0021 _ C3
; main End of function
SECTION .data ; section number 2, data
SECTION .bss ; section number 3, bss
明显的解决方案:
清理objconv
的输出时我犯了一个错误。我应该跑:
sed -i "s/align=1//g ; s/[a-z]*execute//g ; s/: *function//g; /default *rel/d" csimp.asm
所有步骤都可以在bash
脚本中压缩
#! /bin/bash
a=$( echo $1 | sed "s/\.c//" ) # strip the file extension .c
# compile binary with minimal information
gcc -fno-asynchronous-unwind-tables -s -c ${a}.c
# convert the executable to nasm format
./objconv/objconv -fnasm ${a}.o
# remove unnecesairy objconv information
sed -i "s/align=1//g ; s/[a-z]*execute//g ; s/: *function//g; /default *rel/d" ${a}.asm
# run nasm for 64-bit binary
nasm -f elf64 ${a}.asm
# link --> see comment of MichaelPetch below
ld -m elf_x86_64 -s ${a}.o
运行此代码我收到ld
警告:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
以这种方式生成的可执行文件会因分段错误消息而崩溃。我很感激你的帮助。
答案 0 :(得分:4)
我认为您遇到入口点错误的困难是尝试在包含名为ld
的入口点的对象文件上使用main
而ld
正在寻找一个名为_start
的入口点。
有几点需要考虑。首先,如果您要使用C库链接以使用printf
等函数,则链接将main
作为入口点,但如果您没有链接到C库,{{1}将期待ld
。您的脚本非常接近,但您需要一些方法来区分您需要哪个入口点来完全自动化任何源文件的过程。
例如,以下是使用包含_start
的源文件方法的转换。它使用printf
转换为nasm
,如下所示:
生成目标文件:
objconv
使用objconv转换为 nasm 格式的程序集文件
gcc -fno-asynchronous-unwind-tables -s -c struct_offsetof.c -o s3.obj
(注意:我的objconv -fnasm s3.obj
版本添加了DOS行结尾 - 可能错过了一个选项,我只是通过objconv
运行了
使用dos2unix
电话的略微修改版本,调整内容:
sed
(注意:如果没有标准库功能,并且使用sed -i -e 's/align=1//g' -e 's/[a-z]*execute//g' -e \
's/: *function//g' -e '/default *rel/d' s3.asm
,请通过在ld
电话中添加以下表达式将main
更改为_start
sed
(可能有更优雅的表达方式,这只是例如)
使用-e 's/^main/_start/' -e 's/[ ]main[ ]*.*$/ _start/'
进行编译(替换原始对象文件):
nasm
使用nasm -felf64 -o s3.obj s3.asm
获取链接:
gcc
测试
gcc -o s3 s3.obj
答案 1 :(得分:3)
有许多不同的汇编语言 - 对于每个CPU,可能有多种可能的语法(例如&#34; Intel语法&#34;,&#34; AT&amp; T语法&#34;),然后完全不同指令,预处理器等等。它为32位80x86单独添加了大约30种不同的汇编语言。
GCC只能为32位80x86生成一种汇编语言方言。这意味着它无法与NASM,FASM,MASM,TASM,A86 / A386等协同工作。它仅适用于GAS(可能适用于其#34; AT&amp; T模式和#34;可能)。 / p>
当然你可以将3个不同编译器的代码编译成3种不同类型的程序集,然后自己编写3个不同的代码片段(在3种不同类型的程序集中);然后将所有这些(每个都带有适当的汇编程序)组合到目标文件中,并将所有目标文件链接在一起。
答案 2 :(得分:3)
你基本上不能,至少是直接的。 GCC使用Intel语法输出汇编;但NASM / MASM / TASM有自己的英特尔语法。它们主要基于它,但是汇编程序可能无法理解并因此无法编译时存在一些差异。
最接近的可能是objdump
以英特尔格式显示程序集:
objdump -d $file -M intel
Peter Cordes在评论中建议汇编指令仍将以GAS为目标,因此他们不会被NASM认可。它们通常具有相同的名称,但类似GAS的指令以.
开头.section text
(vs section text
)。
答案 3 :(得分:0)
不足以发表评论,但遵循David C. Rankin的上述回答导致重定位错误,并建议我使用-fPIC进行编译。 simp.c:
#include <stdio.h>
int main (void){
int i,j;
for(i=1;i<21;i++){
j= i + 100;
printf("got int: %d\n",j);
}
return(0);
}
然后我运行以下命令:
rm *.obj *.o *.asm
gcc -fno-asynchronous-unwind-tables -s -c simp.c -o simp.obj
objconv -fnasm simp.obj
dos2unix simp.asm
sed -i -e 's/align=1//g' -e 's/[a-z]*execute//g' -e 's/: *function//g' -e '/default *rel/d' simp.asm
nasm -felf64 -o simp2.obj simp.asm
gcc -o my_simp simp2.obj
并出现以下错误:
/usr/bin/ld: simp2.obj: relocation R_X86_64_PC32 against symbol `printf@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status
注意:我尝试在对象编译中使用-fPIC,它确实将extern _GLOBAL_OFFSET_TABLE_
项添加到objconv
生成的nasm中,但实际上并没有使用它。