4

Assume I have the fowling C code, and I'm compiling it on a linux machine with gcc.

test.c:

#include <stdio.h>

int main() {
    printf("hi\n"); 
    return 0;
}

I know that stdio.h defines printf and body of printf exists within the C library in binary format.

Here are my questions:

  1. When doing a normal compile with gcc test.c, does the linker make a dynamic link to printf or a static link?

  2. printf ultimately makes a write() system call. Is the linker copying the C lib defined printf over to the final executable (which will end up calling write() at runtime) or is it copying write() over in the final executable directly.

or in another words: If I open up the executable file and turn in into ascii format, will I see "printf()" in it or "write()"?

  1. If I compile my code and then uninstall the C lib will my code still run? since printf isn't defined anywhere anymore.
Alex
  • 41
  • 2
  • Are you asking what the difference is between dynamic and static linking ? Or are you asking what gcc does by default ? Or something else ? – Sander De Dycker Feb 27 '19 at 13:34
  • 1
    None of this is standardized. I started writing an answer but it doesn't make much sense from a generic point-of-view. You need to narrow this down to a specific system. Linux? – Lundin Feb 27 '19 at 13:55
  • Short (oversimplified) answer: static linking => printf code is copied into the executable, dynamic linking => printf code is not copied into the executable and printf code is in a common library – Jabberwocky Feb 27 '19 at 14:01
  • @Jabberwocky assume i have done a dynamic linking, If I open up the executable file and turn in into ascii format, will I see "printf()" in it or "write()" – Alex Feb 27 '19 at 14:07
  • @Alex that's another (longer) story. Short (again oversimplified answer): it's actually the other way round: if you have static linking, you wont see any symbols (C is a compiled language) even if the `printf` code _is_ included. .With dynamic linking the symbol name of linked function is normally included, but that is platform dependent. Read this: https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work. I think John Bollinger's answer below is good – Jabberwocky Feb 27 '19 at 14:39
  • Other potentially interesting links: https://stackoverflow.com/questions/1993390/static-linking-vs-dynamic-linking, http://cs-fundamentals.com/tech-interview/c/difference-between-static-and-dynamic-linking.php – Jabberwocky Feb 27 '19 at 14:43

2 Answers2

3
  1. When doing a normal compile with gcc test.c, does the linker make a dynamic link to printf or a static link?

It depends. Given that specific compilation command, if a dynamic version of the C library is available, and if GCC is built to use it (both of which are highly likely), then GCC will perform a dynamic link. If only a static version of the C library is available, or if GCC is built or configured to link statically by default, then a static link will be performed.

  1. printf ultimately makes a write() system call. Is the linker copying the C lib defined printf over to the final executable (which will end up calling write() at runtime) or is it copying write() over in the final executable directly.

If GCC is performing a static link then it will copy all functions directly or indirectly required by the program, and maybe others, into the final binary. I'm uncertain about the GNU linker in particular, but some linkers will include the whole target library in the final binary.

  1. If I compile my code and then uninstall the C lib will my code still run? since printf isn't defined anywhere anymore.

If you statically link the C library into your program, then removing the C library afterward will not (directly) prevent your program running. But depending on the details, it might prevent everything else from running, including the GUI, your other applications, and even the shell, thus mooting the question.

Statically linking all required libraries is a reasonable technique for minimizing the runtime dependencies of your binaries, which can improve compatibility with systems differing from the build environment. That does tend to produce much larger binaries, however. In any case, unless you build every program that way, removing the libraries after the fact is not usually a viable alternative.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks, still need to clear this, assume i have done a dynamic linking, If I open up the executable file and turn in into ascii format, will I see "printf()" in it or "write()"? – Alex Feb 27 '19 at 14:44
  • 1
    @Alex, In a dynamically-linked Linux executable that calls the C standard library's `printf()` function, the compiled binary will (probably) contain the string "printf" (no parentheses). It would not necessarily contain the string "write" -- certainly not because of the `printf()` call. In a statically-linked binary with debug information stripped, you would be unlikely to see either. – John Bollinger Feb 27 '19 at 14:47
  • 2
    Note that just because a program calls `printf` does not mean its assembly code will contain “printf”. Compilers may optimize some calls, so that `printf` is not actually called. – Eric Postpischil Feb 27 '19 at 14:50
  • So the translation between printf and write and the final syscall all happens during runtime, so my code (when compiled dynamically) is pretty much useless without the c runtime – Alex Feb 27 '19 at 14:51
  • Yes, @Alex, see what I already wrote in response to your question (3). But I emphasize that on a typical Unix or Linux system, *everything* is dynamically linked against the C library, so the C dynamic library being unavailable is probably not a situation you realistically need to consider. A bigger concern, if you're building a program that will run on a different machine, is that the runtime machine's C library will be incompatible with your program in some way (too old, for example). Accounting for problems of that sort is a reason for static linking. – John Bollinger Feb 27 '19 at 14:54
  • I'm practicing writing a `hello world` kernel, using OsDev wiki, this is where C lib doesn't exist. So trying to put this all together in my head. – Alex Feb 27 '19 at 14:56
  • Well you should have said so, @Alex. If you're writing a kernel, then you simply cannot rely on the C standard library functions *at all*. If you're using GCC for this, then you should be compiling with the [`-ffreestanding`](https://stackoverflow.com/q/17692428/2402272) option, which will avoid linking the C library, among other things. – John Bollinger Feb 27 '19 at 14:59
  • That right, it was actually mentioned in the wiki. But I still wanted to understand this whole linking process a bit better in Unix vs outside of an OS. – Alex Feb 27 '19 at 15:01
2

First, some background. On Unix systems (all that I know of) C runtime contains both standard C functions implementation and so-called glue code (required to call low-level OS functions from C programs).

In your example, printf() is a C runtime function, and write() is a glue interface to write syscall. Assuming we are talking about linux, both would live in glibc library.

When you link your program, by default gcc linker will first try to link to glibc dynamically (using .so). This can be changed, by using -static argument to the linker - it will force static linking of glibc, more can be found here: Static linking of Glibc

You can check the end result by issuing ldd <path to your executable> - this will show you all the .so library requested by the linker.

SergeyA
  • 61,605
  • 5
  • 78
  • 137