繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM