[英]How to generate assembly code with gcc that can be compiled with nasm
我试图将汇编语言作为一种业余爱好学习,并且经常使用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
的输出
编辑 :
我得到的提示是我的问题在另一个问题中得到了解决。 不幸的是,在测试了此处描述的方法之后,我无法生成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
以这种方式生成的可执行文件崩溃,并显示分段错误消息。 多谢您的协助。
我认为您遇到入口错误的困难在于,在ld
正在寻找名为_start
的入口点时 ,试图在包含名为main
的入口点的对象文件中使用ld
。
有两个注意事项。 首先,如果要使用诸如printf
之类的功能与C库链接,则链接将期望main
作为入口点,但如果不与C库链接,则ld
将期望_start
。 您的脚本非常接近,但是您将需要某种方式来区分完全自动化任何源文件过程所需的入口点。
例如,以下是使用包括printf
的源文件的方法进行的转换。 使用objconv
将其转换为nasm
,如下所示:
生成目标文件:
gcc -fno-asynchronous-unwind-tables -s -c struct_offsetof.c -o s3.obj
使用objconv转换为nasm格式的汇编文件
objconv -fnasm s3.obj
(注意:我的objconv
版本添加了DOS行尾-可能错过了一个选项,我只是通过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
,则将以下表达式添加到sed
调用中,将main
更改为_start
)
-e 's/^main/_start/' -e 's/[ ]main[ ]*.*$/ _start/'
(为此可能有更优雅的表达方式,例如)
用nasm
编译(替换原始目标文件):
nasm -felf64 -o s3.obj s3.asm
使用gcc
进行链接:
gcc -o s3 s3.obj
测试
$ ./s3
sizeof test : 40
myint : 0 0
mychar : 4 4
myptr : 8 8
myarr : 16 16
myuint : 32 32
汇编语言有很多不同-每个CPU可能有多种可能的语法(例如“ Intel语法”,“ AT&T语法”),然后是完全不同的指令,预处理器等。 仅对于32位80x86,它就增加了多达30种不同的汇编语言方言。
GCC只能为32位80x86生成一种汇编语言的方言。 这意味着它不能与NASM,FASM,MASM,TASM,A86 / A386等一起使用。它仅适用于GAS(可能还有YASM的“ AT&T模式”)。
当然,您可以使用3种不同的编译器将代码编译为3种不同类型的程序集,然后自己编写3种不同的代码段(3种不同类型的程序集)。 然后将所有这些文件(每个文件都使用适当的汇编程序)组合到目标文件中,并将所有目标文件链接在一起。
您基本上不能,至少直接不能。 GCC以Intel语法进行输出汇编; 但是NASM / MASM / TASM具有自己的Intel语法。 它们在很大程度上是基于此的,但是还有一些差异,汇编器可能无法理解,因此无法编译。
最接近的事情可能是objdump
以Intel格式显示程序集:
objdump -d $file -M intel
彼得·科德斯(Peter Cordes)在评论中建议,汇编程序指令仍将以GAS为目标,因此它们不会被NASM识别。 它们通常具有相同的名称,但类似GAS的指令以开头.
如.section text
(与section text
)一样。
尚不足以发表评论,但遵循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进行对象编译,并且确实向objconv
生成的nasm中添加了一个extern _GLOBAL_OFFSET_TABLE_
条目,但实际上并没有使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.