cgccsystem-callsldstrace

Why do I get extra system calls when compiling code directly to an executable vs. compiling to an object file and then manually linking?


I want to compile this C code with the GNU C Compiler on Ubuntu without linking any standard libraries, having only the following code execute.

static void exit(long long code)
  {asm inline
  ("movq $60,%%rax\n"
  "movq %[code],%%rdi\n"
  "syscall"
  :
  :[code]"rm"(code)
  :"rax"
  ,"rdi");}
static void write(long long fd,char *msg,long long len)
  {asm inline
  ("movq $0x1,%%rax\n"
  "movq %[fd],%%rdi\n"
  "movq %[msg],%%rsi\n"
  "movq %[len],%%rdx\n"
  "syscall"
  :
  :[fd]"rm"(fd)
  ,[msg]"rm"(msg)
  ,[len]"rm"(len)
  :"rax"
  ,"rdi"
  ,"rsi"
  ,"rdx");}
#define PRINT(msg) write(1,msg,sizeof(msg))
void _start()
  {PRINT("Hello World.\n");
  exit(0);}

I compiled with cc example.c -ffreestanding -nostartfiles -O3 -o example.

When I called the output file I saw a lot of extra system calls with strace that should not have been there:

  1. brk
  2. arch_prctl
  3. access
  4. mmap
  5. arch_prctl
  6. mprotect

I then compiled like this: cc example.c -c -O3 -o example.o; ld example.o -o example and it did not do the extra syscalls. It even made the filesize somewhat smaller.

The objdump -d of it was exactly the same. In the objdump -D I found some extra symbols (_DYNAMIC,__GNU_EH_FRAME_HDR,.interp) in the first case compared to the second, but still no sign of any extra syscalls in the code.

Do you know why I get the extra system calls with cc example.c -ffreestanding -nostartfiles -O3 -o example and not with cc example.c -c -O3 -o example.o; ld example.o -o example?


Solution

  • I found out what is happening.

    If I compile the code with cc example.c -ffreestanding -nostartfiles -O3 -o example the compiler makes a dynamically linked executable. Dynamically linked executables have an .interp section. That is what I was seeing in my objdump -D.

    Dynamically linked executables are executing via the program interpreter and the dynamic linker. The additional system calls I saw, came from the dynamic linker. I still do not know why the executable wants to dynamically link anything in a program that does not link any libraries and wants to be freestanding.

    If you do not want the extra system calls from the dynamic linker - you should give gcc the extra -static option. The compiler does not automatically do this if there is no dynamic linking happening.