3

First I want to clarify that I know this question might have been answered hundreds of times. However after hours of Google search I simply couldn't find anything that's exactly what I want. Also even though I've been writing c programs for quite a while, I'm kind of new to nasm and ld. So I would really appreciate it if I can get a simple answer without having to read a whole nasm/ld tutorial or the complete manual.

What I want to do is:
say I have a function written in c that calls some function in the c standard library:

/* foo.c */
#include <stdio.h>
void foo(int i)
{
    printf("%d\n", i);
}

I want to call this function in nasm so I tried this:

; main.asm
global _start
extern foo

section .text
_start:
    push 1234567
    call foo
    add esp, 4

    mov eax, 1
    xor ebx, ebx
    int 80h

Then I tried to compile them and run:

[user ~/Documents/asm/callc]#make all
nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc
[user ~/Documents/asm/callc]#ls
foo.c  foo.o  main  main.asm  main.o  Makefile
[user ~/Documents/asm/callc]#./main 
bash: ./main: No such file or directory
[user ~/Documents/asm/callc]#bash main
main: main: cannot execute binary file

I didn't get any errors but apparently I couldn't run the executable output file.

If the c function doesn't call any library functions then the code above can be compiled and it will run without any problems. I also figured out a way to call library functions directly in nasm and use gcc to produce the final executable file. But none of them is exactly what I want.

EDIT:
1. I'm running 64-bit Ubuntu but I'm trying to write 32-bit programs so I used flags like -m32 and -melf_i386.
2. Output of file *:

[user ~/Documents/asm/sof]#file *
foo.c:     C source, ASCII text
foo.c~:    empty 
foo.o:     ELF 32-bit LSB  relocatable, Intel 80386, version 1 (SYSV), not stripped
main:      ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
main.asm:  C source, ASCII text
main.asm~: empty 
main.o:    ELF 32-bit LSB  relocatable, Intel 80386, version 1 (SYSV), not stripped
Makefile:  makefile script, ASCII text
Makefile~: makefile script, ASCII text

3. I really have no idea of how to tell ld to include the c standard library. I found something like -lglibc or -lc in some other posts. -lgibc doesn't work and -lc seems to be able to get rid of all errors and I probably thought it worked at first but maybe that's the problem since it probably doesn't link the correct library.

UPDATE
Adding -I/lib32/ld-linux.so.2 to the ld command solved my problem.
Below are commands to compile/assemble/link and run the program:

nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc -I/lib32/ld-linux.so.2
./main
uNiverselEgacy
  • 337
  • 3
  • 14
  • 1
    Are you on a 32 or 64 bit Linux system? Run `file *` in that directory, and edit your answer to include the output. Also, although this isn't causing your problem of an invalid executable, you shouldn't expect to call C standard library functions if the C runtime code didn't run first. – Jonathon Reinhart Jan 17 '15 at 02:28
  • 1
    Aside: Why does the prompt look like you're compiling and running stuff as root? :P – cHao Jan 17 '15 at 02:59
  • @cHao Why do you think so? You can customize the prompt however you want so pretty much it can be anything that can be displayed as text. – uNiverselEgacy Jan 17 '15 at 03:17
  • 1
    @uNiverselEgacy: The `#` in the prompt customarily means the shell is running as root. For non-root users, it's usually `$`. There's an escape sequence (`\$`) to display the one that's correct, so either you're running as root, or you've configured the shell to lie. :) – cHao Jan 17 '15 at 03:21
  • @cHao Thanks for the info. I didn't really notice this before. But I don't really like to have a `$` in the prompt so I just configured it to always display `#`. – uNiverselEgacy Jan 17 '15 at 03:31
  • On the whole, I think you're best off not creating `_start` in your assembler code. You might create `main` as the start point. If you create `_start`, you're missing all the normal support code that sorts things out before `main` is called; little things such as 'loading the standard C shared library' etc. – Jonathan Leffler Jan 17 '15 at 08:30
  • I'd echo @cHao's comment about the prompt — don't give the impression of programming as root (or, if you do, expect to be called on it every time). I don't particularly like `$` in the prompt either, so my prompt is normally `Machine JL: ` (the host name, my initials, and a colon-space). But when I answer (or ask) questions on SO, I usually use `$ ` as the prompt, editing what I got on my screen so it matches that. – Jonathan Leffler Jan 17 '15 at 08:33
  • LD needs a special loader: `ld -o main main.o foo.o -melf_i386 -lc -I/lib32/ld-linux.so.2` – rkhb Jan 17 '15 at 09:04
  • @rkhb: It worked! But from some of the comments above and stuff I found online I've been told that some kind of init process has to run first before the standard c library can function. I disassembled the executable file and didn't seem to find code to do that. So I'm not sure why this works or what I've been told is not necessarily true. – uNiverselEgacy Jan 18 '15 at 00:24
  • @JonathanLeffler, I was able to [use `_start` and make standard libraries calls fine using dynamic linkage](http://stackoverflow.com/questions/26358119/static-linkage-with-glibc-without-calling-main). However, I did not manage to do this with static linkage. – Z boson Jan 25 '15 at 03:51

1 Answers1

4

The C library provides code using the _start interface that starts the C runtime, calls main(), and shuts the runtime down. Hence if you intend to use the C library in your program you must not use the _start interface but provide a main() function.

This is the correct way to do it:

; main.asm
global main
extern foo

section .text
main:
    push 1234567
    call foo
    add esp, 4

    xor eax, eax
    ret

Build with:

nasm -f elf32 -o main.o main.asm
gcc -m32 -o foo.o -c foo.c
gcc -m32 -o main main.o foo.o

Two remarks:

  • main() returns, instead of doing an exit system call, to allow the C runtime shutdown code to run.
  • gcc is used for linking. Internally gcc invokes ld with the appropriate parameters to link with the C library. These are platform specific and subject to change. Hence, don't use ld for this.