GNU汇编程序没有生成我可以执行的程序 [英] GNU assembler did not produce a program that I can execute

查看:168
本文介绍了GNU汇编程序没有生成我可以执行的程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着组装一些由gcc生成的中间代码。我使用命令作为-o hello hello.s ,据我所知,它是正确的语法。当我试图运行该程序时,它表示 bash:./hello:无法执行二进制文件。看起来好像汇编代码没有问题,因为它是由gcc生成的代码,而且我怎么调用汇编程序似乎没有什么问题,因为这似乎是正确的语法,根据本手册。任何人都可以帮助我吗?

>假设您的程序集文件名为 hello.s ,并且类似于(假设为32位 Linux 目标):

  .data 
msg:.ascizHello World \\\

msglen =。-msg
.text
。全局_start
_start:
/ *使用int $ 0x80 /​​ eax = 4写入STDOUT * /
/ *输出Hello World * /
mov $ 4,%eax / *写系统调用* /
mov $ 0,%ebx / *文件描述符0 = STDOUT * /
mov $ msg,%ecx / *要输出的消息* /
mov $ msglen,% edx / *消息长度* /
int $ 0x80 /​​ *使系统调用* /

/ *用int $ 0x80 /​​ eax = 1 * /
退出程序mov $ 1,%eax / * 1 =退出系统调用* /
mov $ 0,%ebx / *用* / $ b $退出的值* int $ 0x80 /​​ *进行系统调用* /

这是一个AT& T语法的32位Linux汇编程序,它显示 Hello World 到标准输出使用32位系统调用通过 int $ 0x80 。它不使用任何 C 函数,因此可以使用GNU汇编程序作为进行汇编,并与GNU链接程序 ld链接生成最终的可执行文件。

  as --32 hello.s -o hello.o 
ld -melf_i386 hello.o -o hello

第一行汇编 hello。 s 放入名为 hello.o 的32位 ELF 对象中。然后使用第二个命令将链接到名为 hello 的32位 ELF 可执行文件。 GNU链接器默认假设你的程序在 _start 标签处开始执行。 另外,你可以使用 GCC 来组装和链接这个程序:

  gcc -nostdlib -m32 hello.s -o hello 

这将生成一个名为的32位 ELF 你好 -nostdlib 告诉 GCC 不要在 C 运行时库中链接,并允许我们使用 _start 作为我们程序的入口点。如果你的汇编器程序打算连接到 C 运行库和库,以便它可以使用像 C 这样的函数, em>' printf ,那么事情就有点不同了。假设你有这个程序需要 printf (或任何 C 库函数):

  .data 
msg:.ascizHello World \\\

.text
.global main
main:
push%ebp / *设置堆栈帧* /
mov%esp,%ebp / *堆栈帧使GDB调试更加容易* /

push $ msg / *消息打印* /
调用printf
添加$ 4,%esp / *清理堆栈* /

xor%eax,%eax / *退出时返回0 * /
mov%ebp,%esp / *销毁我们的栈帧* /
pop%ebp
ret / *返回到C运行时,调用我们
并允许它终止程序* /

在大多数* nix类型的系统上,您的入口点现在必须是 main 。原因在于C运行时将有一个名为 _start 的入口点执行 C 运行时初始化,然后生成调用我们在汇编代码中提供的名为 main 的函数。要编译/汇编并链接,我们可以使用:

  gcc -m32 hello.s -o hello 

code>

注意:在Windows上,由 C 运行时调用的入口点是 _WinMain ,而不是 main



使用NASM



在关于 NASM 询问的评论中,我将在与它汇编时提供一些信息。假设你的程序集文件名为 hello.asm ,并且看起来像(不需要 C 运行时库):

  SECTION .data;数据部分
msg dbHello World,13,10
len equ $ -msg

SECTION .text;代码部分
global _start;使标签可用于链接
_start:;标准gcc入口点

mov edx,len;打印字符串的长度
mov ecx,msg;指向字符串
的指针mov ebx,1;写入STDOUT(文件描述符0)
mov eax,4;写命令
int 0x80;中断80十六进制,调用内核

mov ebx,0;退出代码,0 =正常
mov eax,1;将命令退出到内核
int 0x80;中断80十六进制,调用内核

然后将其构建到可执行文件中,可以使用如下命令:

  NASM -f ELF32 hello.asm -o hello.o 
的gcc -nostdlib -m32 hello.o -o你好

第一个命令将 hello.asm 组合到 ELF 目标文件 hello.o 。第二行做链接。 -nostdlib 不包括 C 运行时从链接中(函数如 _printf etc wouldn'不可用)。第二行将 hello.o 链接到可执行文件 hello 另外,您可以跳过使用 GCC 并直接使用链接器:

  nasm -f elf32 hello.asm -o hello.o 
ld -melf_i386 hello.o -o hello

如果您需要 C <运行时和库调用诸如 printf 之类的东西,那么它有点不同。假设您有 NASM 代码需要 printf

  extern printf 

SECTION .data;数据部分,初始化变量

msg:dbHello World,13,10,0

SECTION .text;代码部分。全球主要

;标准的gcc入口点

main:;入口点的程序标签
push ebp;设置堆栈帧
mov ebp,esp;堆栈帧使GDB调试变得更简单

push msg;要打印的消息
调用printf
add esp,4;清理堆栈

mov eax,0;返回值0
mov esp,ebp;销毁我们的堆栈框架
pop ebp
endit:
ret;返回到名为
的C运行库;并允许它执行程序终止

然后将它构建到可执行文件中,可以使用如下命令:

  nasm -f elf32 hello.asm -o hello.o 
gcc -m32 hello.o -o hello


I tried assembling some intermediate code generated by gcc. I used the command as -o hello hello.s, which, as far as I can tell, is the correct syntax. When I tried to run the program, it said bash: ./hello: cannot execute binary file. It doesn't seem like there's a problem with the assembly code, since it was the code generated by gcc, and it doesn't seem like there's anything wrong with how I invoked the assembler, since that seems to be the right syntax according to this manual. Can anyone help me with this?

解决方案

Working with GNU Assembler

Assume that your assembly file is called hello.s and looks something like (assuming a 32-Bit Linux target):

.data
msg:     .asciz "Hello World\n"
msglen = .-msg
.text
.global _start
_start:
    /* Use int $0x80/eax=4 to write to STDOUT */
    /* Output Hello World */
    mov $4, %eax       /* write system call */
    mov $0, %ebx       /* File descriptor 0 = STDOUT */
    mov $msg, %ecx     /* The message to output */
    mov $msglen, %edx  /* length of message */
    int $0x80          /* make the system call */

    /* Exit the program with int $0x80/eax=1 */
    mov $1, %eax       /* 1 = exit system call */
    mov $0, %ebx       /* value to exit with */
    int $0x80          /* make the system call */

This is a 32-bit Linux assembler program in AT&T syntax that displays Hello World to standard output using 32-bit system calls via int $0x80. It doesn't use any C functions so can be assembled with the GNU assembler as and linked with the GNU linker ld to produce a final executable.

as --32 hello.s -o hello.o
ld -melf_i386 hello.o -o hello

The first line assembles hello.s into a 32-bit ELF object called hello.o . hello.o is then linked to a 32-bit ELF executable called hello with the second command. The GNU linker assumes by default that your program starts execution at the label _start .

Alternatively you can use GCC to assemble and link this program with this command:

gcc -nostdlib -m32 hello.s -o hello

This will produce a 32-bit ELF executable called hello . The -nostdlib tells GCC not to link in the C runtime library and allows us to use _start as our program's entry point.

If your assembler program is intended to be linked to the C runtime and library so that it can utilize functions like C's printf then things are a bit different. Assume you have this program that needs printf (or any of the C library functions):

.data
msg: .asciz "Hello World\n"
.text
.global main
main:
    push %ebp          /* Setup the stack frame */
    mov %esp, %ebp     /* Stack frames make GDB debugging easier */

    push  $msg         /* Message to print */
    call  printf
    add   $4,%esp      /* cleanup the stack */

    xor %eax, %eax     /* Return 0 when exiting */
    mov %ebp, %esp     /* destroy our stack frame */
    pop %ebp
    ret                /* Return to C runtime that called us
                          and allow it to do program termination */

Your entry point now must be mainon most *nix type systems. The reason is that the C runtime will have an entry point called _start that does C runtime initialization and then makes a call to the function called main which we supply in our assembler code. To compile/assemble and link this we can use:

gcc -m32 hello.s -o hello

Note: on Windows the entry point called by the C runtime is _WinMain, not main.

Working with NASM

In the comments you also asked about NASM so I'll provide some information when assembling with it. Assume that your assembly file is called hello.asm and looks something like (It doesn't require the C runtime libraries):

SECTION .data       ; data section
msg     db "Hello World", 13, 10
len     equ $-msg

SECTION .text       ; code section
    global _start     ; make label available to linker
_start:               ; standard  gcc  entry point

mov edx,len     ; length of string to print
mov ecx,msg     ; pointer to string
mov ebx,1       ; write to STDOUT (file descriptor 0)
mov eax,4       ; write command
int 0x80        ; interrupt 80 hex, call kernel

mov ebx,0       ; exit code, 0=normal
mov eax,1       ; exit command to kernel
int 0x80        ; interrupt 80 hex, call kernel

Then to build it into an executable you can use commands like these:

nasm -f elf32 hello.asm -o hello.o 
gcc -nostdlib -m32 hello.o -o hello

The first command assembles hello.asm to the ELF object file hello.o . The second line does the linking. -nostdlib excludes the C runtime from be linked in (functions like _printf etc wouldn't be available). The second line links hello.o to the executable hello .

Alternatively you can skip using GCC and use the linker directly like this:

nasm -f elf32 hello.asm -o hello.o 
ld -melf_i386 hello.o -o hello

If you need the C runtime and library for calling things like printf then it is a bit different. Assume you have this NASM code that needs printf:

    extern  printf

SECTION .data           ; Data section, initialized variables

    msg:      db   "Hello World", 13, 10, 0

SECTION .text           ; Code section.

    global main         ; the standard gcc entry point

main:                   ; the program label for the entry point
    push    ebp         ; Setup the stack frame
    mov     ebp, esp    ; Stack frames make GDB debugging easier

    push    msg         ; Message to print
    call    printf
    add     esp, 4      ; Cleanup the stack

    mov     eax, 0      ; Return value of 0
    mov     esp, ebp    ; Destroy our stack frame
    pop     ebp
endit:
    ret                 ; Return to C runtime that called us
                        ; and allow it to do program termination

Then to build it into an executable you can use commands like these:

nasm -f elf32 hello.asm -o hello.o
gcc -m32 hello.o -o hello

这篇关于GNU汇编程序没有生成我可以执行的程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆