================================= Some standard library for the ULM ================================= Besides its core language a programming language typically also defines a __standard library__, in the case of C the __C standard library__. For the ULM C dialect we will rebuild some parts of the C standard library. Currently the ULM C compiler only translates source code into assembly code for the ULM instruction set. Use your imagination that it also could produce assembly code for other architectures, e.g. the Intel Architecture or ARM architecture. That means code written for the ULM C compiler is platform independent in the sense that it just needs to be re-compiled on each platform. So obviously we want to write as much as possible in C and as few as possible in assembly. Porting the library to another platform then only requires to adapt the assembly fraction. Initial code base for the library used in this session ====================================================== ---- SHELL (path=session12/libulm, hide) --------------------------------------- make clean mkdir -p /home/numerik/pub/libulm_initial rm /home/numerik/pub/libulm_initial/* cp * /home/numerik/pub/libulm_initial -------------------------------------------------------------------------------- On `theon` the directory `/home/numerik/pub/libulm_initial/` contains all sources files for the library, some test programs and a makefile: ---- SHELL (path=/home/numerik/pub/libulm_initial) ----------------------------- pwd ls -------------------------------------------------------------------------------- The makefile is a derivate from Session 11. It allows that source files are written in C or assembly: :import: session12/libulm/Makefile [fold] As usual a simple `make` will build everything, i.e. the library and the test programs: ---- SHELL (path=/home/numerik/pub/libulm_initial) ----------------------------- make -------------------------------------------------------------------------------- So for instance a "hello, world" program implemented in C: ---- SHELL (path=/home/numerik/pub/libulm_initial) ----------------------------- xhello_in_c -------------------------------------------------------------------------------- And with `make clean` all generated files are deleted: ---- SHELL (path=/home/numerik/pub/libulm_initial) ----------------------------- make clean -------------------------------------------------------------------------------- Storing test programs and source files in a single directory is certainly not the right thing to do when you have a larger project but sufficient in our case. Like in the previous session we use a simple naming convention so that the build system can differentiate between them, i.e. files that begin with 'x' are test programs all other are part of the library. However, you should get at least some impression what a kind of demands a proper build system should satisfy. First of all, it should be possible to add, delete or rename source files. Also, intermediate files (like object files) should only kept around if they can be used to speedup rebuilding the project. Source code for the library --------------------------- Files with extension ".c" or ".s" that do not begin with an "x" are source files for the library implemented in C or assembly respectively: ---- SHELL (path=/home/numerik/pub/libulm_initial) --------------------------- ls [^x]*.[cs] ------------------------------------------------------------------------------ The dependencies for building the static library can be described as follows: ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{flowchart.tex} \renewcommand\BoxWidth {3} \renewcommand\FlowColDist {5} \renewcommand\BoxHeight {1.2} \renewcommand\BoxDistance {2.2} \SetMargin{1}{2}{1}{1} \renewcommand\FlowCol {0} \PutStatement{1}{crt0.s} \PutStatement[densely dashed]{2}{crt0.o} \renewcommand\FlowCol {1} \PutStatement{1}{putchar.s} \PutStatement[densely dashed]{2}{putchar.o} \renewcommand\FlowCol {2} \PutStatement{0}{puts.c} \PutStatement[densely dashed]{1}{puts.s} \PutStatement[densely dashed]{2}{puts.o} \renewcommand\FlowCol {3} \PutStatement{1}{putui.s} \PutStatement[densely dashed]{2}{putui.o} \renewcommand\FlowCol {1} \PutStatement[very thick]{4}{libulm.a} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{0}{2}{0}{1}{generated from} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{1}{2}{1}{1}{generated from} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{2}{1}{2}{0}{generated from} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{2}{2}{2}{1}{generated from} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{3}{2}{3}{1}{generated from} \AddDepPath{1}{4}{2}{2}{} \AddDepPath{1}{4}{1}{2}{} \AddDepPath{1}{4}{3}{2}{} \AddDepPath[above=1cm,fill=white,draw,rounded corners]{1}{4}{0}{2}{stored members} \end{tikzpicture} ------------------------------------------------------------------------------ With `make libulm.a` the build system only generates or updates the library: ---- SHELL (path=/home/numerik/pub/libulm_initial) --------------------------- make libulm.a ------------------------------------------------------------------------------ Note that all object files, and also assembly files generated from C code, are deleted afterwards. That's because they would not speedup the rebuild time. For example, if you would modify `puts.c` then you always have to regenerated `puts.s` and `puts.o`: ---- SHELL (path=/home/numerik/pub/libulm_initial) ----------------------------- touch puts.c make libulm.a -------------------------------------------------------------------------------- So there is no benefit from keeping these intermediate files. For a quick look here are the library source files viewable in the browser: :import: session12/libulm/crt0.s [fold] :import: session12/libulm/putchar.s [fold] :import: session12/libulm/puts.c [fold] :import: session12/libulm/putui.s [fold] Test programs ------------- Files that begin with a 'x' refer to a test program that can be written in C or assembly. Hence, these are the initial test programs: ---- SHELL (path=/home/numerik/pub/libulm_initial) --------------------------- ls x*.[cs] ------------------------------------------------------------------------------ Each test program gets translated into an object file and linked against the library: ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{flowchart.tex} \renewcommand\BoxWidth {3} \renewcommand\FlowColDist {5} \renewcommand\BoxHeight {1.2} \renewcommand\BoxDistance {2.2} \SetMargin{1}{2}{1}{1} \renewcommand\FlowCol {0} \PutStatement{1}{xanswer.s} \PutStatement{2}{xanswer.o} \PutStatement{4}{xanswer} \renewcommand\FlowCol {1} \PutStatement{0}{xhello\_in\_c.c} \PutStatement[densely dashed]{1}{xhello\_in\_c.s} \PutStatement{2}{xhello\_in\_c.o} \PutStatement{4}{xhello\_in\_c} \renewcommand\FlowCol {2} \PutStatement{1}{xhello.s} \PutStatement{2}{xhello.o} \PutStatement{4}{xhello} \renewcommand\FlowCol {3} \PutStatement[very thick]{2}{libulm.a} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{0}{2}{0}{1}{generated from} \AddDepPath{0}{4}{3}{2}{} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{0}{4}{0}{2}{linked} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{1}{1}{1}{0}{generated from} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{1}{2}{1}{1}{generated from} \AddDepPath{1}{4}{3}{2}{} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{1}{4}{1}{2}{linked} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{2}{2}{2}{1}{generated from} \AddDepPath{2}{4}{3}{2}{} \AddDepPath[above right=0.2cm,fill=white,draw,rounded corners]{2}{4}{2}{2}{linked} %\AddDepPath{1}{4}{2}{2}{} %\AddDepPath{1}{4}{1}{2}{} %\AddDepPath{1}{4}{3}{2}{} %\AddDepPath[above=1cm,fill=white,draw,rounded corners]{1}{4}{0}{2}{stored members} \end{tikzpicture} ------------------------------------------------------------------------------ For generating specific test programs pass them as arguments to `make`. For instance, this just creates `xhello_in_c` ---- SHELL (path=/home/numerik/pub/libulm_initial) --------------------------- make xhello_in_c ulm xhello_in_c ------------------------------------------------------------------------------ Quiz 15: Make `puts` standard conform ====================================== In this exercise you are supposed to change the implementation of `puts` so that it conforms to the __C standard library__, read here the man page of __function `puts`__. On success it returns a non-negative value on success and otherwise `EOF` which is a implementation dependant macro (in most implementation it expands to -1). For getting an idea why `puts` in general can fail read __When will puts() fail?__ on __stackoverflow__. On the ULM calling `puts` will always succeed so changing the implementation has the sole purpose of being compliant. This is for instanced achieved by this implementation that always returns zero (most implementations in the real world would return the number of printed characters): ---- CODE (type=c) ------------------------------------------------------------- extern void putchar(char ch); int puts(char *str) { while (*str) { putchar(*str); ++str; } return 0; } -------------------------------------------------------------------------------- So what is it that you have to do? You should get a taste of the consequences when you change the interface of a library: Adapt the test programs `xhello.s` and `xhello_in_c.c` so that the work together with the new `puts` function. On `theon` submit the source files as follows: `submit hpc quiz15 xhello.s xhello_in_c.c` :links: standard library -> https://en.wikipedia.org/wiki/Standard_library C standard library -> https://en.wikipedia.org/wiki/C_standard_library function `puts`-> https://pubs.opengroup.org/onlinepubs/009695399/functions/puts.html When will puts\(\) fail\? -> https://stackoverflow.com/questions/37198647/when-will-puts-fail stackoverflow -> https://stackoverflow.com