views:

601

answers:

6

I wonder if I could write a program in the C-programming language that is executable, albeit not using a single library call, e.g. not even exit()?

If so, it obviously wouldn't depend on libraries (libc, ld-linux) at all.

A: 

Well, you would need to use some system calls to load all it's information into memory, so I doubt it.

And you would almost have to use exit(), just because of the way that Linux works.

samoz
+4  A: 

Yes, it is possible, however you will have to make system calls and set up your entry point manually.

Example of a minimal program with entry point:

.globl _start
.text
_start:
    xorl %eax,%eax
    incl %eax
    movb $42, %bl
    int $0x80

Or in plain C (no exit):

void __attribute__((noreturn)) _start() {
    while(1);
}

Compiled with:

gcc -nostdlib -o example example.s
gcc -nostdlib -o example example.c
Alex B
Very nice answer. In a strict sense, it is the right answer, because it is pure C without inline asm. I've chosen litb's answer as the correct one as it explains additionally how to perform system calls. Thank you, Checkers.
prinzdezibel
+6  A: 

I suspect you could write such a thing, but it would need to have an endless loop at the end, because you can't ask the operation system to exit your process. And you couldn't do anything useful.

Well start with compiling an ELF program, look into the ELF spec and craft together the header, the program segments and the other parts you need for a program. The kernel would load your code and jump to some initial address. You could place an endless loop there. But without knowing some assembler, that's hopeless from the start on anyway.

The start.S file as used by glibc may be useful as a start point. Try to change it so that you can assemble a stand-alone executable out of it. That start.S file is the entry point of all ELF applications, and is the one that calls __libc_start_main which in turn calls main. You just change it so it fits your needs.

Ok, that was theoretical. But now, what practical use does that have?

Answer to the Updated Question

Well. There is a library called libgloss that provides a minimal interface for programs that are meant to run on embedded systems. The newlib C library uses that one as its system-call interface. The general idea is that libgloss is the layer between the C library and the operation system. As such, it also contains the startup files that the operation system jumps into. Both these libraries are part of the GNU binutils project. I've used them to do the interface for another OS and another processor, but there does not seem to be a libgloss port for Linux, so if you call system calls, you will have to do it on your own, as others already stated.

It is absolutely possible to write programs in the C programming language. The linux kernel is a good example of such a program. But also user programs are possible. But what is minimally required is a runtime library (if you want to do any serious stuff). Such one would contain really basic functions, like memcpy, basic macros and so on. The C Standard has a special conformance mode called freestanding, which requires only a very limited set of functionality, suitable also for kernels. Actually, i have no clue about x86 assembler, but i've tried my luck for a very simple C program:

/* gcc -nostdlib start.c */
int main(int, char**, char**);

void _start(int args)
{
    /* we do not care about arguments for main. start.S in 
     * glibc documents how the kernel passes them though.
     */
    int c = main(0,0,0);

    /* do the system-call for exit. */
    asm("movl   %0,%%ebx\n" /* first argument */
        "movl   $1,%%eax\n" /* syscall 1 */
        "int    $0x80"      /* fire interrupt */
        : : "r"(c) :"%eax", "%ebx");
}

int main(int argc, char** argv, char** env) {
    /* yeah here we can do some stuff */
    return 42;
}

We're happy, it actually compiles and runs :)

Johannes Schaub - litb
I revised my question as it was misleading. I don't want to write a program with no system calls, but rather one that doesn't need to link against the c library.
prinzdezibel
+2  A: 

In pure C? As others have said you still need a way to make syscalls, so you might need to drop down to inline asm for that. That said, if using gcc check out -ffreestanding.

Logan Capaldo
A: 

You'd need a way to prevent the C compiler from generating code that depends on libc, which with gcc can be done with -fno-hosted. And you'd need one assembly language routine to implement syscall(2). They're not hard to write if you can get suitable OS doco. After that you'd be off to the races.

Norman Ramsey
A: 

Yes you can, but it's pretty tricky.

There is essentially absolutely no point.

You can statically link a program, but then the appropriate pieces of the C library are included in its binary (so it doesn't have any dependencies).

You can completely do without the C library, in which case you need to make system calls using the appropriate low-level interface, which is architecture dependent, and not necessarily int 0x80.

If your goal is making a very small self-contained binary, you might be better off static-linking against something like uclibc.

MarkR