=================================================== C By Example Part 3: Compiler, Assembler and Linker [TOC] =================================================== ---- VIDEO ------------------------------ https://www.youtube.com/embed/3UJEnXUUi3U ----------------------------------------- Exercises ========= Practice your editor skills and create following files in a directory of your choice: - File `foo.c` with ---- CODE (file=session05/cbe/foo.c) ------------------- void bar(void); int main() { bar(); } -------------------------------------------------------- - File `bar.c` with ---- CODE (file=session05/cbe/bar.c) ------------------- int printf(const char *, ...); void bar() { printf("foo bar\n"); } -------------------------------------------------------- Translate the source files into an executable ============================================= First use the following one-line command and check that the executable does what you expect: ---- SHELL (path=session05/cbe) --------------------------- gcc foo.c bar.c a.out ----------------------------------------------------------- Of course you also do things more manual. And you will see there are reasons why this is of advantage. For example with ---- SHELL (path=session05/cbe) --------------------------- gcc -S foo.c gcc -c foo.s gcc -S bar.c gcc -c bar.s gcc foo.o bar.o a.out ----------------------------------------------------------- we invoke the tools one by one. Actually except for the preprocessor which will be invoked together with the compiler when you use the option `-S`. Quiz 5 ====== Assume that for some reason it is actually of advantage (food for thought) to translate the source files step by step with one of the following commands: ---- CODE (type=txt) ------ gcc -S foo.c gcc -c foo.s gcc -S bar.c gcc -c bar.s gcc foo.o bar.o --------------------------- Also assume that you already did this. But then you had to modify file `bar.c` because you came up with a great idea to improve its implementation: ---- BOX -------- What commands do you need to re-run to generate an executable. Of course the number of commands should be minimal. Write this commands in the order you have to execute them into a file `quiz05.txt`. Submit your solution with `submit hpc quiz05 quiz05.txt`. If you do not get an error message the submission was successful. ----------------- Using the ULM C Compiler on theon ================================= In the video you will see that the ULM C Compiler `ucc` can be used to observe the generated assembly code, object file and executable. In order to use `ucc` on `theon` you have to add the directory of the installation to your path: ---- CODE (type=sh) ------------------- export PATH=$PATH:/home/numerik/pub/bin --------------------------------------- To make this permanent append the above line to your `.bashrc`. For example with ---- CODE (type=sh) ------------------------------------------- echo 'export PATH=$PATH:/home/numerik/pub/bin' >> $HOME/.bashrc --------------------------------------------------------------- or alternatively (but do not do both) with ---- CODE (type=sh) ------------------------------------------- echo 'export PATH=$PATH:/home/numerik/pub/bin' >> ~/.bashrc --------------------------------------------------------------- Limitations of the ULM Compiler ------------------------------- Note that currently the ULM C compiler only supports a (serious) subset of the C programming language. Here a list of _unsupported features_: - __Floating point types__, e.g. `float`, `double`, `complex float` and `complex double`. - __`switch` statements__. - Labels and __`goto` statements__. - __Bit fields__. - Large parts of the C standard library. Testing the ULM Compiler ------------------------ Like with `gcc` you can compile the two C source files into an executable with this one-line command: ---- SHELL (path=session05,hide) -------------------------- rm -rf session05/ucc mkdir ucc cp -r cbe/* ucc/ ----------------------------------------------------------- ---- SHELL (path=session05/ucc) --------------------------- ucc foo.c bar.c a.out ----------------------------------------------------------- Or you can generate intermediate results (except the result of the preprocessor) as follows: ---- SHELL (path=session05/ucc) --------------------------- ucc -S foo.c ucc -c foo.s ucc -S bar.c ucc -c bar.s ucc foo.o bar.o a.out ----------------------------------------------------------- Also have a look into the generated files. For educational purposes the output format of the object files and executable is a readable text file. So for the sake of education we waste some space on the hard disk: - Assembly files `foo.s` and `bar.s` :import: session05/ucc/foo.s [fold] :import: session05/ucc/bar.s [fold] - Object files `foo.o` and `bar.o` :import: session05/ucc/foo.o [fold] :import: session05/ucc/bar.o [fold] - The executable `a.out` :import: session05/ucc/a.out [fold] No Error Message means ... ========================== ... the compiler tools could not help you to find the errors in your code. So you are on your own :( Usually beginners in programming do not like error messages, but they should. Because the above statement will often be true. Here an example for a program that compiles perfectly but crashes terribly when you run it. The problem might be obvious. But in general the same type of problem can be hidden with within several thousands lines of code: - File `foo.c` with ---- CODE (file=session05/cbe2/foo.c) ----------------- void bar(void); int main() { bar(); } -------------------------------------------------------- - File `bar.c` with ---- CODE (file=session05/cbe2/bar.c) ------------------ int bar = 42; -------------------------------------------------------- This compiles without any error or even warning into an executable: ---- SHELL (path=session05/cbe2) -------------------------- gcc -Wall foo.c bar.c ----------------------------------------------------------- And this happens when you run it (it will run, but just for a few instructions): ---- SHELL (path=session05/cbe2) -------------------------- a.out echo $? ----------------------------------------------------------- :links: Floating point types -> https://en.cppreference.com/w/c/language/arithmetic_types `switch` statements -> https://en.cppreference.com/w/cpp/language/switch `goto` statements -> https://en.cppreference.com/w/cpp/language/goto Bit fields -> https://en.cppreference.com/w/cpp/language/bit_field