/* Andrzej Wasowski, IT University of Copenhagen, 2005 APR 30 */ /* Consider running the following process in order to trace the various stages: 1. Invoke the preprocessor: cpp hello.c hello.cpp This saves the preprocessed version of hello.c in hello.cpp. Peek inside and note that comments are removed, and the literal MSG is inlined. 2. Compile the file: cc -c hello.cpp -o hello.o This creates a compiled binary version of hello.o. You may also run cc directly on hello.c, which has the effect of implicit call to the preprocessor first. 3. You may run objdump, to see that indeed hello.o contains a function main: objdump -t hello.o Note (at the bottom) that main function code is indicated, while printf is marked "UND" (undefined). This is because printf is an external function that needs to be *linked* from a library. 4. Manual linking becomes a bit cumbersome nowadays (with the GCC startup code being split across multiple files). Instead run it via gcc and ask for verbose option output: cc -static hello.o -o hello -v On my machine this creates a 500KB executable file, which can be executed without access to any external libraries. 5. Alternatively call cc -shared hello.o -o hello-shared -v obtaining a dynamically linked program hello-shared. On my machine this is a 6.5k file, which requires external files from /usr/lib to be present during execution (in particular glibc library). Run objdump -T hello-static to verify that no external symbols remain in the static version. While objdump -T hello-shared reveales that some symbols remained unresolved and will require loading of libraries at execution time. */ #define MSG "Hello, world!\n" extern int printf(const char *format, ...); int main(int argc, const char * argv[]) { printf (MSG); return 0; }