如何使用可以使用nasm编译的gcc生成汇编代码

时间:2016-01-30 13:11:28

标签: gcc assembly 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

的输出,我就可以解决这个问题

修改

我得到了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 

以这种方式生成的可执行文件会因分段错误消息而崩溃。我很感激你的帮助。

4 个答案:

答案 0 :(得分:4)

我认为您遇到入口点错误的困难是尝试在包含名为ld的入口点的对象文件上使用mainld正在寻找一个名为_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中,但实际上并没有使用它。