2

How do you build a C program that includes the entry point on Mac OS X?

I want to build:

start() {
    /* exit system call */
    asm("movl $1,%eax;"
        "xorl %ebx,%ebx;"
        "int  $0x80"
    );
}

but when I run:

gcc -nostdlib min.c

I always get:

ld: could not find entry point "start" (perhaps missing crt1.o)
collect2: ld returned 1 exit status

The one other attempt I made just to see what it was doing was run:

gcc -nostdlib -c min.c && otool -tV min.o

And the output was:

(__TEXT,__text) section
_start:
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp,%rbp
0000000000000004    leave
0000000000000005    ret

So where did that underscore come from before the "start" function? How do I prevent that from happening? Or more simply:

How do you build a C program that includes the entry point on Mac OS X?

Thanks, CrazyChenz

Crazy Chenz
  • 12,650
  • 12
  • 50
  • 62
  • _start is a mangled name, probably. Before you create a start, be aware that there is a lot of preprocessing that has to go on or all sorts of problems will break. To get an idea of symbols you have to define try nm crt1.o. gcc -e main makes "main" the entry point instead of start. You can define any function you want this way. I do not know how to set that option for Xcode. Someone else might. – jim mcnamara Dec 04 '10 at 15:16
  • IIRC, MacOS call numbers are different from Linux, so eax=1 / int 0x80 might not be sys_exit. And 32-bit system MacOS calls take their args on the stack FreeBSD style, not EBX, ECX, EDX, .... And of course if making a 64-bit executable, you'll want to use `syscall` with appropriate call numbers / arg-passing regs for that. – Peter Cordes Feb 20 '20 at 03:45

2 Answers2

3

You can control the symbol that gcc gives to the function by declaring it separately with asm:

void start() asm ("start");

Make sure this is a standalone declaration, separate from the function definition.

You can read more details about controlling the generated symbol here: https://stackoverflow.com/a/1035937/12928775

Also, as Peter Cordes points out, you should probably include __attribute__((naked)) on the function definition to prevent gcc from generating a stack frame on entry.

The full code would be:

void start() asm ("start");

__attribute__((naked)) void start() {
    /* exit system call */
    asm("movl $1,%eax;"
        "xorl %ebx,%ebx;"
        "int  $0x80"
    );
}
Sofia Faro
  • 51
  • 3
  • 2
    You don't need `extern` in the prototype. https://godbolt.org/z/Vz77nS shows that `void start(void) asm("_mystart");` produces the specified name. Also, you probably want `void` instead of using legacy C implicit-`int`. And `__attribute__((naked))` would be a good idea for the definition; `start` isn't a function so you don't want -O0 to make a stack frame on entry. – Peter Cordes Feb 20 '20 at 03:42
  • 2
    For extra bonus points, remember that `()` in C (unlike C++) leaves the arg types unspecified, not like `(void)`. Might as well be specific that it doesn't take any args. – Peter Cordes Feb 20 '20 at 08:28
2

The gcc -e option defines the entry point, when you want the entry point to be something other than start. This way you can create mystart() as you entry point.

gcc -e mystart mycode.c -o mycode

I do not know how to set the -e option in Xcode.

jim mcnamara
  • 16,005
  • 2
  • 34
  • 51