简体   繁体   中英

NASM Hello World on Linux: undefined reference to `main'

I've been following this tutorial for an intro to assembly on Linux.

section .text
global _start ;must be declared for linker (ld)

_start:
        mov edx,len     ;message length
        mov ecx,msg     ;message to write
        mov ebx,1       ;file descriptior
        mov eax,4       ;system call number (sys_write)
        int 0x80        ;call kernel

        mov eax,1       ;system call number (sys_exit)
        int 0x080       ;call kernel

section .data

msg db 'Hello, world!', 0xa     ;the string
len equ $ - msg                 ;length of the string

I've then had problems compiling it. I've looked around and found (on SO) that I should compile it like this:

nasm -f elf64 hello.asm
gcc -o hello hello.o

But I keep getting this error from GCC:

hello.o: In function `_start':
hello.asm:(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

(NB: I'm running Debian Linux on a 64 bit Intel i7)

If you are going to learn assembly, then you are much better served learning to use the assembler nasm and the linker ld without relying on gcc . There is nothing wrong with using gcc , but it masks part of the linking process that you need to understand going forward.

Learning assembly in the current environment (generally building on x86_64 but using examples that are written in x86 32-bit assembler), you must learn to build for the proper target and the language ( syscall ) differences between the two. Your code example is 32-bit assembler. As such your nasm compile string is incorrect:

nasm -f elf64 hello.asm

The -f elf64 attempts to compile a 64-bit object file, but the instructions in your code are 32-bit instructions. (It won't work)

Understanding and using ld provides a better understanding of the differences. Rather than using gcc , you can use nasm and ld to accomplish the same thing. For example (with slight modification to the code):

msg db 0xa, 'Hello, StackOverflow!', 0xa, 0xa     ;the string

You compile and build with:

nasm -f elf -o hello-stack_32.o hello-stack_32.asm
ld -m elf_i386 -o hello-stack_32 hello-stack_32.o

Note the use of -f elf for 32-bit code in the nasm call and the -m elf_i386 linker option to create a compatible executable.

output:

Hello, StackOverflow!

If you are serious about learning assembler, there are a number of good references on the web. One of the best is The Art of Assembly . (it is written primarily for 8086 and x86 , but the foundation it provides is invaluable). In addition, looking at the executables you create in binary can be helpful. Take a look at Binary Vi (BVI) . It is a good tool.

bvi screenshot

在此处输入图片说明

链接二进制文件时,应添加-nostdlib

gcc -o hello hello.o -nostdlib

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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