Searene
Searene

Reputation: 27564

Mixing programming of assembly and C in linux

There are only two files, main.c and kernel.asm, and I tried to make a program with them using NASM and GCC. contents are as follows:

main.c

#include <stdio.h>

void Print_String() {
    printf("Hello World!\n");
}

kernle.asm

extern Print_String

[section .text]
global _start
_start:
    call Print_String

Compile and Link:

nasm -f elf -o kernel.o kernel.asm
gcc -c -o main.o main.c
ld -s -lc -o final kernel.o main.o

Then I run the final file with the command: ./final, but the result is depressing:

bash: ./final: No such file or directory

However, the current directory does have the file final, for the command ls, it displays:

final  kernel.asm  kernel.o  main.c  main.o

So why it cannot find the file final? Is there anything wrong? Any help appreciated!

Upvotes: 3

Views: 1227

Answers (3)

vonbrand
vonbrand

Reputation: 11791

Very simple: there is no main() to call in the program... thus whatever you do, the C-program-startup machinery doesn't get a hold.

Upvotes: 0

Rich Drummond
Rich Drummond

Reputation: 3509

It is not that it cannot find it, per se. The error message is somewhat misleading. The dynamic linker cannot resolve its dependencies, and thus your program image is not loadable (and not executable)

The problem is that you are dynamically linking against libc without any other of the paraphernalia to make dynamic linking actually work. Thus you are left with a binary image that cannot be loaded.

You might find that it's easier to statically link against libc. This can be done as follows:

ld -Bstatic -o final kernel.o main.o -lc

Notice you have to move the '-lc' bit after the code module main.o which uses it.

If you try this, you'll get a whole bunch of unresolved symbols. That's because you will also need to link against libgcc and libgcc_eh.

The following got me fairly close (apologies, working on a 64-bit system here):

ld -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/32/ -melf_i386 -Bstatic -lc -o final kernel.o main.o -lc -lgcc -lgcc_eh

This failed for me with

/usr/lib/gcc/x86_64-linux-gnu/4.4.3/32//libgcc_eh.a(unwind-dw2-fde-glibc.o): In function `_Unwind_Find_FDE':
(.text+0x193b): undefined reference to `dl_iterate_phdr'

Which doesn't make much sense. You may have more luck linking 32-bit on a 32-bit system.

Update

Apologies for the ramble above. I had a think about this again, and, of course, it is possible to make dynamic linking work. The missing piece is to specify the dynamic linker:

In my case, this was:

ld -dynamic-linker /lib32/ld-linux.so.2 -melf_i386 -o final kernel.o main.o -lc

So for you the following should work:

ld -dynamic-linker /lib/ld-linux.so.2 -o final kernel.o main.o -lc

Update again

In response to markzar's comment - you have to make a syscall to cleanly exit. This has the effect of doing something similar to exit(0) in C:

mov eax,1  ; Syscall #1       
mov ebx,0  ; Return code 0 = success
int 80H

Upvotes: 4

Ziffusion
Ziffusion

Reputation: 8923

Try this. First change kernel.asm as follows:

extern Print_String

[section .text]
global main
main:
    call Print_String

Then use the following commands to create the executable (instead of the linker).

nasm -f elf -o kernel.o kernel.asm
gcc -c -o main.o main.c
gcc -o final kernel.o main.o

Upvotes: 1

Related Questions