14

I'm learning assembly programming. Below is the simple program that prints 'Hello, World!'. While the program runs perfectly, I'm getting the warning message while loading

ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080

Here is the code :

section .data
    msg db 'Hello, world!', 0xa
    len equ $ - msg

section .text
    global main

main:

    mov ebx, 1
    mov ecx, msg
    mov edx, len
    mov eax, 4
    int 0x80

    mov eax, 1
    int 0x80

Can anybody explain the meaning of this warning. I'm using nasm with ubuntu 14.

Peter Cordes
  • 245,674
  • 35
  • 423
  • 606
Atinesh
  • 1,392
  • 5
  • 24
  • 46
  • 2
    I'm not an assembly guru, but I believe the assembler is looking for an entry point called `_start` (which it cannot find because it isn't there). Stack Overflow seems pretty ripe with questions similar to this one, so please have a search around. – Tim Biegeleisen Jan 13 '16 at 05:13
  • 1
    @TimBiegeleisen Actually I also thought that. But what I'm not getting here is that why is it working with `main`. Why `nasm` throughs warning instead of error, if it want `start_` explicitly. I've googled it and found everyone is using `start_` keyword in their assembly code, But why is it working with `main` keyword. – Atinesh Jan 13 '16 at 05:23
  • 3
    _"Why nasm throughs warning instead of error"_. From what I can see the warning comes from the linker, not from nasm. The linker couldn't find the entrypoint, so it probably defaults to the beginning of the `.text` section. – Michael Jan 13 '16 at 06:44
  • related: https://stackoverflow.com/questions/10995118/cannot-find-entry-symbol-start/11595056 – Ciro Santilli新疆棉花TRUMP BAN BAD Aug 18 '18 at 21:22

7 Answers7

10

Use the label _start instead of main for the ELF entry point. main implies it's like the C main function, but this isn't even a function (e.g. you can't ret).


You don't say, but from the error messages and code I assume you're building your 32bit code with nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o

(If you're actually building 64bit code, you're lucky that it happens to work, but it'll break as soon as you do anything with esp instead of rsp.)

The error message is from ld, not from nasm. It says so right in the message. Tim's comment is correct: ld looks for a _start symbol in the files it links, but sets the entry point to the beginning of the text segment if it doesn't find one.

It doesn't matter what other global/external symbols you define. main has no relevance at all here, and could point anywhere you want. It's only useful for a disassembly output and stuff like that. Your code would work exactly the same if you took out the global main / main: lines, or changed them to any other name.


Labelling that as main is unwise because the ELF entry point is not a function. It's not main(), and doesn't receive argc and argv arguments, and can't ret because ESP is pointing at argc instead of a return address.

Only use main if you link with gcc / glibc's CRT startup code that looks for a main symbol and calls it after initializing libc. (So functions like printf work. Technically dynamic linker hooks let libc initialize itself before your _start if you linked it, but generally don't do that unless you understand exactly what you're doing). Related: Assembling 32-bit binaries on a 64-bit system (GNU toolchain)

e.g. gcc -m32 -o hello main.o if you do define a main:
instead of gcc -m32 -static -nostdlib -o hello start.o
(which is equivalent to your bare ld).

Peter Cordes
  • 245,674
  • 35
  • 423
  • 606
  • Actually in the tutorial I'm using they have used `main` instead of `start_`. – Atinesh Jan 14 '16 at 10:47
  • 1
    @Atinesh: Then you should build with `gcc -m32 -o hello32 hello32.o`, instead of `ld` directly, so the standard libc startup code runs first, and calls your `main` function. I assume the next step in the tutorial is going to use some libc functions or something (although you can still do that from `_start` by linking with libc). Or maybe the tutorial isn't very good. There's no good reason to label your entry point `main`. Or if you do, you should use `-e main` to tell the linker it's the entry point, instead of leaving a confusing warning in your tutorial. – Peter Cordes Jan 14 '16 at 15:28
  • 1
    The 32-bit elf loader passes the parameters and environment variables on the stack but not in the way _C_ `main` function would expect them. 0(esp) is argc, 4(esp) is argv[0](program name), then each subsequent value on the stack is a pointer to each of the remaining arguments,followed by a NULL pointer, and then each stack value is a pointer to each of the environment variables followed by a NULL pointer. There are other pointers and values after that, but beyond what is typically used by most assembly programs. – Michael Petch Jan 16 '16 at 05:05
5

I would suggest that you link your object files (however they are produced) with gcc, not ld.

gcc will call ld with the appropriate options, since it knows more about the source code and will create whatever is necessary for the assumptions that ld makes.

tzot
  • 81,264
  • 25
  • 129
  • 197
3

I do not know if this is a valid fix, but seems to work for me:

try using option

--entry main

while linking your kernel C code.

ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary --entry main 
  • 2
    That's the right answer to a *different* question. This question is about creating a Linux ELF executable to run under Linux, not a stand-alone kernel. Using `--entry main` would just be confusing for this, as I explained in my answer. Only call your function `main` if it's called by something that passes it `argv` and `argc`, and that it can `ret` to when it's done. – Peter Cordes Oct 04 '20 at 08:51
2

You can try to compile the assembly source file with nasm, generate the *.o file, and then use the ld link the *.o file with parameter -e main. This means that main is specified as the program entry.

chunlin Li
  • 21
  • 2
  • 1
    That's just confusing because `main` is normally used as a name for a function that runs after the C library init functions are done, so you can use `printf` and so on. To do that from the ELF entry point, you need to call glibc init functions yourself (or use dynamic linking). So it's best to keep calling your ELF entry point `_start`, and only use `main` for the function called from CRT startup code. – Peter Cordes May 26 '18 at 11:43
2

Instead of main you should use _start to indicate where nasm assembler should start executing. foe eg:

section .text
global _start
_start:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
coddygeek
  • 105
  • 1
  • 11
0

To compile and execute your program you can create bash script as follow:

compile64.sh

!/bin//bash
echo "Assembling with Nasm"
nasm -f elf64 -o $1.o $1.asm
echo "Linking ... "
gcc -o $1 $1.o
echo "Done !"

$ ./compile64 nameOftheFile  (without extension)
Usman Khan
  • 3,052
  • 4
  • 30
  • 76
Adi H.
  • 9
  • 1
-1

there is some issue in your programs like some syntactical mistakes like you can not assign registers value to constant because constant can not hold any value, for storing constants value we use variable

while assembling your program i am getting below mentioned asseble time errors

no such instruction: msg db 72ello,world!440xa' assign.S:3: Error: no such instruction:len equ $ - msg' assign.S:4: Error: no such instruction: section .text' assign.S:5: Error: no such instruction:global main' assign.S:7: Error: too many memory references for mov' assign.S:8: Error: too many memory references formov' assign.S:9: Error: too many memory references for mov' assign.S:10: Error: too many memory references formov' assign.S:11: Error: operand size mismatch for int' assign.S:12: Error: too many memory references formov' assign.S:13: Error: operand size mismatch for `int'

Here is code which give you same output on your gnu compiler with 32bit intel processor

.section .rodata msgp: .string "Hello World"

    .section .text
    .globl  main
    .type   main,@function

main:
    pushl   $msgp
    call    printf
    addl    $4,%esp

    pushl   $0
    call    exit

save this code with some name latest take Hello.S asseble with $ as -o Hello.o Hello.S link with $ ld -o Hello.o -lc -dynamic-linker /lib.ld.linux.so.2 -e main -Hello.o To run $ ./Hello

hope it will help you

  • 1
    You got errors because as the person asking the question said they are using `nasm`. You are using GNU assembler (`as`) which uses a different syntax. – Michael Petch Sep 04 '19 at 23:23