===================================================== Print an unsigned integer (and about the BSS segment) [TOC] ===================================================== The next thing we need to do is printing an integer. More precisely, an unsigned integer as this obviously makes sense when we compute the factorial. As before we first develop a standalone component that just does this job. Assignment: quiz04 ================== Write a program `printuint.s` that prints the unsigned value stored in its data segment at label `n`. So a skeleton for this program is given by ---- CODE (file=printuint.s) --------------------------------------------------- .data n .byte 123 .text /* Your code that prints the unsigned byte at label n */ -------------------------------------------------------------------------------- On `theon` submit your program with the following command ---- CODE (type=txt) ----------------------------------------------------------- submit hpc quiz04 printuint.s -------------------------------------------------------------------------------- Using the ULM tools =================== Recall from __session 5__ that the command line tools (`ulm`, `ulmas`) only run on theon. The debugger `ulm-qui` and `ulm-qui-random-memory` only work on `heim` (and for `ssh` you then have to use option flag `-X`). Video tutorial ============== The problem that you have to solve is similar to reading an integer. Basically your just doing things the way around. Recall, for reading an integer you have to read single characters, compute their numerical value and "attach the digits" to assemble the integer value. Now, for printing the integer you have to print the value digit by digit. Part one: printing the digits in reverse order (because that is simple) ----------------------------------------------------------------------- Let's say $n$ is an unsigned integer with $k$ decimal digits, i.e. ---- LATEX --------------------------------------------------------------------- n = (d_{k-1}, \dots, d_0)_{10} := \sum\limits_{i=0}^{k-1} d_i \cdot 10^i -------------------------------------------------------------------------------- then in a first step we compute the digits (in sequential order) by ---- LATEX --------------------------------------------------------------------- \begin{array}{lcrlcr} d_0 & \leftarrow & n \bmod 10,\; & n & \leftarrow & \left\lfloor \frac{n}{10} \right\rfloor \\ d_1 & \leftarrow & n \bmod 10,\; & n & \leftarrow & \lfloor \frac{n}{10} \rfloor \\ & \vdots & & & \vdots & \\ d_{k-1} & \leftarrow & n \bmod 10,\; & n & \leftarrow & \left\lfloor \frac{n}{10} \right\rfloor \\ \end{array} -------------------------------------------------------------------------------- And even if we don't know the number of digits it is no problem. We just stop when $n$ becomes zero. So an algorithm that prints all digits is simple ---- CODE (type=txt) ----------------------------------------------------------- do { d <- n mod 10 n <- n div 10 print digit d } while n > 0 -------------------------------------------------------------------------------- For the (integer) division the ULM provides the two instructions __divq__ and __idivq__. Both compute the quotient _and_ the remainder. So this makes it even simpler. There is only one problem: It would print the digits in reverse order, i.e. $d_0 \dots d_{k-1}$ instead of $d_{k-1} \dots d_0$. But anyway, havin that is a good starting point. And there are already a few things to do just to get that far. And here the video about that ---- VIDEO ------------------------------ https://www.youtube.com/embed/Gjtta_Bu6Zg ----------------------------------------- Part two: printing the digits in the right order ------------------------------------------------ For bringing the digits into the right order, we can first write the to memory instead of printing them immediately. Once all digits were generated (and written to memory) we read them back in reverse order and print them. Before you start to figure out the technical details (e.g. what instructions are needed) first think about it a bit more general: - We need at most 20 memory cells for the digits. That is because the maximum number of decimal digits of a 64-bit unsigned integer is given by $\left\lceil \frac{64 \cdot \log 2}{\log 10} \right\rceil $. And we need an extra byte to mark the end of the string. That means we need 21 memory cells that can be used to store the characters for the digits. Initially these cells will be zero initialized. For referring to these cells we also need to know the address of the first memory cell. Let's use a label `buf` for that: ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \DrawMemArrayOpen{0}{20} \DrawMemLabel{0}{buf} \DrawPointer{0}{\%P} \DrawMemCellContent{0}{\texttt{0}} \DrawMemCellContent{1}{\texttt{0}} \DrawMemCellContent{2}{\texttt{0}} \DrawMemCellContent{3}{\texttt{0}} \DrawMemCellContent{4}{\texttt{0}} \DrawMemCellContent{5}{\texttt{0}} \DrawMemCellContent{6}{\texttt{0}} \DrawMemCellContent{7}{\texttt{0}} \DrawMemCellContent{8}{\texttt{0}} \DrawMemCellContent{9}{\texttt{0}} \DrawMemCellContent{10}{\texttt{0}} \DrawMemCellContent{11}{\texttt{0}} \DrawMemCellContent{12}{\texttt{0}} \DrawMemCellContent{13}{\texttt{0}} \DrawMemCellContent{14}{\texttt{0}} \DrawMemCellContent{15}{\texttt{0}} \DrawMemCellContent{16}{\texttt{0}} \DrawMemCellContent{17}{\texttt{0}} \DrawMemCellContent{18}{\texttt{0}} \DrawMemCellContent{19}{\texttt{0}} \DrawMemCellContent{20}{\texttt{0}} \end{tikzpicture} ------------------------------------------------------------------------------ Note that a register `%P` is used to store a pointer to the first memory cell. - Before we write the first digit to memory we increment the pointer. So we have ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \DrawMemArrayOpen{0}{20} \DrawMemLabel{0}{buf} \DrawPointer{1}{\%P} \DrawMemCellContent{0}{\texttt{0}} \DrawMemCellContent{1}{\texttt{0}} \DrawMemCellContent{2}{\texttt{0}} \DrawMemCellContent{3}{\texttt{0}} \DrawMemCellContent{4}{\texttt{0}} \DrawMemCellContent{5}{\texttt{0}} \DrawMemCellContent{6}{\texttt{0}} \DrawMemCellContent{7}{\texttt{0}} \DrawMemCellContent{8}{\texttt{0}} \DrawMemCellContent{9}{\texttt{0}} \DrawMemCellContent{10}{\texttt{0}} \DrawMemCellContent{11}{\texttt{0}} \DrawMemCellContent{12}{\texttt{0}} \DrawMemCellContent{13}{\texttt{0}} \DrawMemCellContent{14}{\texttt{0}} \DrawMemCellContent{15}{\texttt{0}} \DrawMemCellContent{16}{\texttt{0}} \DrawMemCellContent{17}{\texttt{0}} \DrawMemCellContent{18}{\texttt{0}} \DrawMemCellContent{19}{\texttt{0}} \DrawMemCellContent{20}{\texttt{0}} \end{tikzpicture} ------------------------------------------------------------------------------ - Say that the first digit is 3 then we would write its ASCII value to the address `%P`: ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \DrawMemArrayOpen{0}{20} \DrawMemLabel{0}{buf} \DrawPointer{1}{\%P} \DrawMemCellContent{0}{\texttt{0}} \DrawMemCellContent{1}{\texttt{'3'}} \DrawMemCellContent{2}{\texttt{0}} \DrawMemCellContent{3}{\texttt{0}} \DrawMemCellContent{4}{\texttt{0}} \DrawMemCellContent{5}{\texttt{0}} \DrawMemCellContent{6}{\texttt{0}} \DrawMemCellContent{7}{\texttt{0}} \DrawMemCellContent{8}{\texttt{0}} \DrawMemCellContent{9}{\texttt{0}} \DrawMemCellContent{10}{\texttt{0}} \DrawMemCellContent{11}{\texttt{0}} \DrawMemCellContent{12}{\texttt{0}} \DrawMemCellContent{13}{\texttt{0}} \DrawMemCellContent{14}{\texttt{0}} \DrawMemCellContent{15}{\texttt{0}} \DrawMemCellContent{16}{\texttt{0}} \DrawMemCellContent{17}{\texttt{0}} \DrawMemCellContent{18}{\texttt{0}} \DrawMemCellContent{19}{\texttt{0}} \DrawMemCellContent{20}{\texttt{0}} \end{tikzpicture} ------------------------------------------------------------------------------ The same way we proceed for the remaining digits. - When all digits were computed and the corresponding ASCII value written to memory we want that register `%P` points to the first digit that gets printed. So for an integer $n=123$ we want the following situation: ---- TIKZ -------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \DrawMemArrayOpen{0}{20} \DrawMemLabel{0}{buf} \DrawPointer{3}{\%P} \DrawMemCellContent{0}{\texttt{0}} \DrawMemCellContent{1}{\texttt{'3'}} \DrawMemCellContent{2}{\texttt{'2'}} \DrawMemCellContent{3}{\texttt{'1'}} \DrawMemCellContent{4}{\texttt{0}} \DrawMemCellContent{5}{\texttt{0}} \DrawMemCellContent{6}{\texttt{0}} \DrawMemCellContent{7}{\texttt{0}} \DrawMemCellContent{8}{\texttt{0}} \DrawMemCellContent{9}{\texttt{0}} \DrawMemCellContent{10}{\texttt{0}} \DrawMemCellContent{11}{\texttt{0}} \DrawMemCellContent{12}{\texttt{0}} \DrawMemCellContent{13}{\texttt{0}} \DrawMemCellContent{14}{\texttt{0}} \DrawMemCellContent{15}{\texttt{0}} \DrawMemCellContent{16}{\texttt{0}} \DrawMemCellContent{17}{\texttt{0}} \DrawMemCellContent{18}{\texttt{0}} \DrawMemCellContent{19}{\texttt{0}} \DrawMemCellContent{20}{\texttt{0}} \end{tikzpicture} ------------------------------------------------------------------------------ For writing a byte from a register use the instruction __movb__. The instruction copies the least significant byte from a register to a specified address in memory. For example ---- CODE (type=s) ------------------------------------------------------------- movb %1, (%2) -------------------------------------------------------------------------------- copies $\text{val} := u(\%1) \bmod 2^8$ to the memory cell with address $u(\%2)$: ---- TIKZ ---------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \DrawMemArrayOpen{0}{6} \DrawPointer{2}{\%2} \DrawMemCellContent{2}{val} \end{tikzpicture} -------------------------------------------------------------------------------- So where in memory can we write the 21 bytes? We could use the data segment. For example, with ---- CODE ---------------------------------------------------------------------- .data buf .byte 0 .byte 0 ... .byte 0 -------------------------------------------------------------------------------- the executable would contain a data segment with 21 zero initialized bytes (if we did not miscount when writing the `.byte` directives). But there is an easier way. An executable can contain beside a text and data segment a so called __BSS__ segment. When an executable gets loaded into memory the program loaded copies the text and data segment to memory and in addition zero initializes a memory region as specified in the BSS segment. In the assembly program we can describe your BSS segment as follows: ---- CODE ---------------------------------------------------------------------- .bss buf .space 21 # 21 bytes -------------------------------------------------------------------------------- Here the video about that: ---- VIDEO ------------------------------ https://www.youtube.com/embed/TLnPJ5eBxJM ----------------------------------------- :links: divq -> http://www.mathematik.uni-ulm.de/numerik/hpc/ss20/hpc0/ulm.pdf#page=11 idivq -> http://www.mathematik.uni-ulm.de/numerik/hpc/ss20/hpc0/ulm.pdf#page=14 session 5 -> doc:session05/page01 movb -> http://www.mathematik.uni-ulm.de/numerik/hpc/ss20/hpc0/ulm.pdf#page=29 BSS -> https://en.wikipedia.org/wiki/.bss More about the BSS segment ========================== In the video the BSS segment was introduced for zero initialized data. Consider the following program to see how this is realized: ---- CODE(file=session08/bss/ex1.s) -------------------------------------------- .data LabelA: .byte 42 .bss LabelB: .space 4 LabelC: .space 4 .text LabelD: halt 0 -------------------------------------------------------------------------------- Now translate it ---- SHELL (path=session08/bss ) ----------------------------------------------- ulmas -o ex1 ex1.s -------------------------------------------------------------------------------- and look at the assembler output: :import: session08/bss/ex1 You see that there is a new section for the BSS segment: - The header has the format `BSS `. Unlike the text segment the are now subsequent lines for the BSS segment with data. The `` and `` attributes is all information the loader needs to initialize the segment. Because the alignment is 1 the BSS segment will start right after the data segment. - Also note that the symbol table contains the symbols `LabelB` and `LabelC` of type _bss_. When you load this with `ulm-qui-random-memory` you will see the following memory layout: ---- TIKZ ---------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \renewcommand\MemCellWidth { 1 } \DrawMemArrayOpenRight{0}{18} \DrawMemVariable[white]{13}{19}{\dots random values \dots} \DrawMemAddress{0}{0x0} \DrawMemCellContent{0}{09} \DrawMemCellContent{1}{00} \DrawMemCellContent{2}{00} \DrawMemCellContent{3}{00} \DrawMemCellContent{4}{2A} \DrawMemCellContent{5}{00} \DrawMemCellContent{6}{00} \DrawMemCellContent{7}{00} \DrawMemCellContent{8}{00} \DrawMemCellContent{9}{00} \DrawMemCellContent{10}{00} \DrawMemCellContent{11}{00} \DrawMemCellContent{12}{00} \end{tikzpicture} -------------------------------------------------------------------------------- From the description of the sections you can interpret this as follows: ---- TIKZ ---------------------------------------------------------------------- \begin{tikzpicture} \input{memory.tex} \renewcommand\MemCellWidth { 1 } \DrawMemArrayOpenRight{0}{14} \DrawMemAddress{0}{0x0} \DrawMemAddress{4}{0x4} \DrawMemAddress{5}{0x5} \DrawMemAddress{9}{0x9} \DrawMemLabel{0}{LabelD} \begingroup \renewcommand\MemLabelHeight {1} \DrawMemLabel{4}{LabelA} \par\endgroup \DrawMemLabel{5}{LabelB} \DrawMemLabel{9}{LabelC} \DrawMemVariable[gray!50]{0}{4}{} \DrawMemVariable[orange!50]{4}{5}{} \DrawMemVariable[blue!50]{5}{13}{} \DrawMemCellContent{0}{09} \DrawMemCellContent{1}{00} \DrawMemCellContent{2}{00} \DrawMemCellContent{3}{00} \DrawMemCellContent{4}{2A} \DrawMemCellContent{5}{00} \DrawMemCellContent{6}{00} \DrawMemCellContent{7}{00} \DrawMemCellContent{8}{00} \DrawMemCellContent{9}{00} \DrawMemCellContent{10}{00} \DrawMemCellContent{11}{00} \DrawMemCellContent{12}{00} \end{tikzpicture} -------------------------------------------------------------------------------- :navigate: up -> doc:index back -> doc:session08/page03 next -> doc:session08/page05