[SPCA] Finish stack, data type compilation details

This commit is contained in:
2026-01-12 12:02:53 +01:00
parent 639c147264
commit 9da3a2c0d3
23 changed files with 255 additions and 156 deletions

View File

@@ -1,61 +0,0 @@
\newpage
\subsection{The syntax}
There are two common styles: AT\&T syntax (common on UNIX) and Intel syntax (common on Windows)
The state that is visible to us is:
\begin{itemize}
\item PC (Program Counter) that contains the address of the next instruction
\item Register file that contains the most used program data
\item Condition codes that store status information about most recent arithmetic operation and are used for conditional branching
\end{itemize}
To view what \lC\ code looks like in assembly, we can use \texttt{gcc -O0 -S code.c}, which produces \texttt{code.s} which contains assembly code.
\subsubsection{Registers}
\texttt{x86} assembly is a bit particular with register naming (register names all start in \%).
The initial 16-bit version of \texttt{x86} had the following registers (sub registers are registers that can be used to access the high
(\texttt{h} suffix) or low (\texttt{l} suffix) half of the register. Only registers ending in \texttt{x} feature these sub registers.
They, as well as \texttt{\%si} and \texttt{\%di} are general purpose):
\begin{tables}{lll}{Name & Sub-registers & Description}
\texttt{\%ax} & \texttt{\%ah}, \texttt{\%al} & accumulate \\
\texttt{\%cx} & \texttt{\%ch}, \texttt{\%cl} & counter \\
\texttt{\%dx} & \texttt{\%dh}, \texttt{\%dl} & data \\
\texttt{\%bx} & \texttt{\%bh}, \texttt{\%bl} & base \\
\texttt{\%si} & - & Source index \\
\texttt{\%di} & - & Destination index \\
\hline
\texttt{\%sp} & - & Stack pointer \\
\texttt{\%bp} & - & Base pointer \\
\texttt{\%ip} & - & Instruction pointer \\
\texttt{\%sr} & - & Status (flags) \\
\end{tables}
When the architecture was extended to 32-bit, all registers previously available were retained and a 32 bit version of each was introduced with the prefix \texttt{e}.
In other words, any 16 bit code would still work as previously, as e.g. the \texttt{\%ax} register was simply now the lower 16 bits of the \texttt{\%eax} register.
The same happened again when extending to 64-bit, only this time the \texttt{r} prefix was used.
So, the register \texttt{\$eax} was now the lower 32 bits of \texttt{\%rax}.
Additionally, the following registers are also available, with \texttt{X} to be substituted with 8 through 15: \texttt{\%rX} and the lower 32 bits \texttt{\%rXd}
\subsubsection{Instructions}
Instructions usually have a 3 letter \texttt{mnemonic} with a one letter postfix that indicates the number of bytes.
The following postfixes are available: \texttt{b} (byte, 1 byte), \texttt{w} (word, 2 bytes), \texttt{l} (long word, 4 bytes) and \texttt{q} (quad, 8 bytes).
The following options can be passed for source and destination: Registers,
\content{Immediates} To use a constant value (aka Immediate) in an instruction, we prefix the number with \texttt{\$} (following number is decimal).
To use hex, we can use \texttt{\$0x}, etc.
\content{Memory addresses} To treat a register as a memory address, use parenthesis, e.g. \texttt{(\%rax)} interprets the value of \texttt{\%rax} as a memory address.
The instruction will then read the number of bytes, as specified by the postfix of the instruction.
The full syntax for memory address modes is \texttt{D(Rb, Ri, S)}, where
\begin{itemize}[noitemsep]
\item \texttt{D}: Displacement (constant offset), can be 0, 1, 2 or 4 bytes (not bits, if you are confused as I was)
\item \texttt{Rb}: Base register (to which offsets, etc are added). Can be any of the 16 integer registers
\item \texttt{Ri}: Index register: Any, except for \texttt{\%rsp} (and \texttt{\%rbp} is also rarely used)
\item \texttt{S}: Scale factor (1, 2, 4 or 8, to correct offsets)
\end{itemize}
The computation that happens is the following: \texttt{Mem[ Reg[Rb] + S * Reg[Ri] + D ]}.
Using the \texttt{lea src, dest} instruction, we can get the address computed into the dest register.
Can be abused for similar arithmetic expressions.

View File

@@ -0,0 +1,12 @@
\newpage
\subsection{The syntax}
There are two common styles: AT\&T syntax (common on UNIX) and Intel syntax (common on Windows)
The state that is visible to us is:
\begin{itemize}
\item PC (Program Counter) that contains the address of the next instruction
\item Register file that contains the most used program data
\item Condition codes that store status information about most recent arithmetic operation and are used for conditional branching
\end{itemize}
To view what \lC\ code looks like in assembly, we can use \texttt{gcc -O0 -S code.c}, which produces \texttt{code.s} which contains assembly code.

View File

@@ -0,0 +1,25 @@
\subsubsection{Registers}
\texttt{x86} assembly is a bit particular with register naming (register names all start in \%).
The initial 16-bit version of \texttt{x86} had the following registers (sub registers are registers that can be used to access the high
(\texttt{h} suffix) or low (\texttt{l} suffix) half of the register. Only registers ending in \texttt{x} feature these sub registers.
They, as well as \texttt{\%si} and \texttt{\%di} are general purpose):
\begin{tables}{lll}{Name & Sub-registers & Description}
\texttt{\%ax} & \texttt{\%ah}, \texttt{\%al} & accumulate \\
\texttt{\%cx} & \texttt{\%ch}, \texttt{\%cl} & counter \\
\texttt{\%dx} & \texttt{\%dh}, \texttt{\%dl} & data \\
\texttt{\%bx} & \texttt{\%bh}, \texttt{\%bl} & base \\
\texttt{\%si} & - & Source index \\
\texttt{\%di} & - & Destination index \\
\hline
\texttt{\%sp} & - & Stack pointer \\
\texttt{\%bp} & - & Base pointer \\
\texttt{\%ip} & - & Instruction pointer \\
\texttt{\%sr} & - & Status (flags) \\
\end{tables}
When the architecture was extended to 32-bit, all registers previously available were retained and a 32 bit version of each was introduced with the prefix \texttt{e}.
In other words, any 16 bit code would still work as previously, as e.g. the \texttt{\%ax} register was simply now the lower 16 bits of the \texttt{\%eax} register.
The same happened again when extending to 64-bit, only this time the \texttt{r} prefix was used.
So, the register \texttt{\$eax} was now the lower 32 bits of \texttt{\%rax}.
Additionally, the following registers are also available, with \texttt{X} to be substituted with 8 through 15: \texttt{\%rX} and the lower 32 bits \texttt{\%rXd}

View File

@@ -0,0 +1,22 @@
\subsubsection{Instructions}
Instructions usually have a 3 letter \texttt{mnemonic} with a one letter postfix that indicates the number of bytes.
The following postfixes are available: \texttt{b} (byte, 1 byte), \texttt{w} (word, 2 bytes), \texttt{l} (long word, 4 bytes) and \texttt{q} (quad, 8 bytes).
The following options can be passed for source and destination: Registers,
\content{Immediates} To use a constant value (aka Immediate) in an instruction, we prefix the number with \texttt{\$} (following number is decimal).
To use hex, we can use \texttt{\$0x}, etc.
\content{Memory addresses} To treat a register as a memory address, use parenthesis, e.g. \texttt{(\%rax)} interprets the value of \texttt{\%rax} as a memory address.
The instruction will then read the number of bytes, as specified by the postfix of the instruction.
The full syntax for memory address modes is \texttt{D(Rb, Ri, S)}, where
\begin{itemize}[noitemsep]
\item \texttt{D}: Displacement (constant offset), can be 0, 1, 2 or 4 bytes (not bits, if you are confused as I was)
\item \texttt{Rb}: Base register (to which offsets, etc are added). Can be any of the 16 integer registers
\item \texttt{Ri}: Index register: Any, except for \texttt{\%rsp} (and \texttt{\%rbp} is also rarely used)
\item \texttt{S}: Scale factor (1, 2, 4 or 8, to correct offsets)
\end{itemize}
The computation that happens is the following: \texttt{Mem[ Reg[Rb] + S * Reg[Ri] + D ]}.
Using the \texttt{lea src, dest} instruction, we can get the address computed into the dest register.
Can be abused for similar arithmetic expressions.

View File

@@ -1,6 +0,0 @@
\subsection{Data types}
\begin{itemize}
\item ``\texttt{Integer}'' data type of 1, 2, 4 or 8 bytes that are data values or addresses (untyped pointers)
\item ``\texttt{Floating point}'' data type of 4, 8 or 10 bytes
\item No aggregate types (such as arrays, structs, etc)
\end{itemize}

View File

@@ -0,0 +1,19 @@
\subsection{Data types}
Assembly supports the following integer types (where GAS stands for GNU Assembly).
If they are signed or unsigned does not matter (as we have seen), so it's up to you to interpret them as one or the other
\begin{tables}{llll}{Intel & GAS & Bytes & \lC}
byte & \texttt{b} & 1 & \texttt{[unsigned] char} \\
word & \texttt{w} & 2 & \texttt{[unsigned] short} \\
double word & \texttt{l} & 4 & \texttt{[unsigned] int} \\
quad word & \texttt{q} & 8 & \texttt{[unsigned] long} \\
\end{tables}
These integer types are also used for pointer addresses.
Assembly also supports floating point numbers.
They are stored and operated on in floating point registers.
\begin{tables}{llll}{Intel & GAS & Bytes & \lC}
single & \texttt{s} & 4 & \texttt{float} \\
double & \texttt{l} & 8 & \texttt{double} \\
extended & \texttt{t} & 16 & \texttt{long double} \\
\end{tables}
Assembly does not support any aggregate types (such as arrays, structs, etc) natively.
You can however (obviously) make your own. In the following section we will cover how \lC\ datatypes are compiled into assembly.

View File

@@ -0,0 +1,7 @@
\subsubsection{Arrays}
Arrays of type \texttt{T} and length \texttt{L} are allocated as a contiguous region of memory with size \texttt{L * sizeof(T)} bytes.
We then also store a reference / identifier \texttt{A} to the array (i.e. similar to variable name in \lC), that holds the address of the first
element of the array and can then be used in conjunction with ``assembly pointer arithmetic''.
Array loops that are written as for-loops in code are usually transformed into do-while loops by the compiler to save one condition check in the beginning,
except of course, it might be possible that the loops is never executed.

View File

@@ -0,0 +1,24 @@
\subsubsection{Structures}
We again allocate a contiguous region of memory.
Only now, the number of bytes required isn't as straight forward to compute anymore, it is still not hard:
We simply sum up the sizes of all members and that will be our required sizes, so for the $n$ members $x_i$ of struct \texttt{my\_struct}, we have
$\texttt{sizeof(my\_struct)} = \sum_{i = 0}^{n - 1} \texttt{sizeof}(x_i)$.
However, the size of a struct may be different to fulfill alignment requirements set forth by the ISA or operating system.
This could mean that the struct takes \texttt{n * K} bytes, where \texttt{K} is the alignment of the largest element
For alignment on \texttt{x86-64} we have:
\mrmvspace
\begin{multicols}{2}
\begin{itemize}[noitemsep]
\item 1 byte (no restrictions)
\item 2 bytes (LSB must be 0)
\item 4 bytes (2 LSB must be 00)
\item 8 bytes (3 LSB must be 000)
\item 16 bytes (4 LSB must be 0000)
\end{itemize}
\end{multicols}
\dhrmvspace
Another issue is accessing members. The solution to this is however easy and efficient, as at compile time, the offsets are pre-determined
and compiled into the setter and/or getter code for the struct.

View File

@@ -0,0 +1,14 @@
\subsubsection{Nested / Multidimensional arrays, Struct arrays}
All of these arrays have similar underlying concepts in the way they are allocated, yet all are a bit different
\content{Common ideas} Each of the array's elements are allocated in contiguous regions of memory, with the elemnts also in contiguous regions of memory.
(Imagine it as lining up all elements on a band, i.e. as going through the array in a nested loop and printing all the elements into a single line.)
The size of the array is determined by \texttt{n * sizeof(T)}, where \texttt{T} is the type of the elements of the array (or outer array).
This is what is different for the lot (as well as accessing elements):
\content{Nested array} \texttt{T} is another array. We thus have a recursive definition, where \texttt{sizeof(T)} resolves to \texttt{n * sizeof(T1)}, etc.
Accessing element $i$, $j$, $k$ is handled as follows: $o = i * \texttt{sizeof(T)} + j * \texttt{sizeof(T1)} + k * \texttt{sizeof(T2)}$,
with \texttt{T1} and \texttt{T2} the types of the nested arrays
\content{Struct arrays} \texttt{T} is a struct.

View File

@@ -0,0 +1,8 @@
\subsubsection{Multi-Level arrays}
In comparison to multidimensional arrays, we have arrays of pointers that contain either more arrays of pointers, (normal) arrays or pointers to other data types.
The size of such a Multi-Level array is determined by:
\texttt{n * sizeof(ptr)}, where \texttt{sizeof(ptr)} is the platform-specific size of a pointer and \texttt{n} is the number of elements in the array
To do an access, we need to do two (or more) memory reads, which we can again do using address computations.
The benefit of these kinds of arrays is that we can store arbitrary data types together in an array, giving us more flexibility.

View File

@@ -0,0 +1,2 @@
\subsubsection{Unions}
Since unions can hold any of the elements listed (but only one at a time), we allocate based on the size of the largest element.

View File

@@ -1,83 +0,0 @@
\subsection{Operations}
Assembly operations include performing arithmetic or logic functions on registers or memory data,
transferring data between memory and registers and transferring control (conditional or unconditional jumps).\\
Note that \verb|move| instructions \textit{cannot} move data directly from memory to memory.
The following instruction formats are commonly used:
\inputcodewithfilename{gas}{code-examples/01_asm/}{00_operations.s}
Arithmetic / logic operations need a size postfix (replace \texttt{X} below with \texttt{b} (1B), \texttt{w} (2B), \texttt{l} (4B) or \texttt{q} (8B)).
\begin{tables}{lll}{Mnemonic & Format & Computation}
\texttt{addX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest + Src} \\
\texttt{subX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest - Src} \\
\texttt{imulX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest * Src} \\
\texttt{salX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest << Src} \\
\texttt{sarX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest >> Src} (arithmetic) \\
\texttt{shrX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest >> Src} (logical) \\
\texttt{xorX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest \string^ Src} \\
\texttt{andX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest \& Src} \\
\texttt{orX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest | Src} \\
\texttt{incX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{Dest + 1} \\
\texttt{decX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{Dest - 1} \\
\texttt{negX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{-Dest} \\
\texttt{notX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{\string~Dest} \\
\end{tables}
\newpage
\subsubsection{Condition Codes}
Any arithmetic operation (that is truly part of the arithmetic operations group, so not including \texttt{lea} for example) implicitly sets the \bi{condition codes}.
The following condition codes were covered in the lecture (operation: \texttt{t = a + b}):
\begin{itemize}
\item \texttt{CF} (Carry Flag): Set if carry out from MSB (unsigned overflow)
\item \texttt{ZF} (Zero Flag): Set if \texttt{t == 0}
\item \texttt{SF} (Sign Flag): Set if \texttt{(a - b) < 0} (for signed)
\item \texttt{OF} (Overflow Flag): Set if two's complement overflow (i.e. \verb+(a>0 && b>0 && t<0) || (a<0 && b<0 && t>=0)+)
\end{itemize}
\content{Explicit computation}
In the below explanations, we always assume \texttt{src2 = b} and \texttt{src1 = a}
To explicitly compute them, we can use the \texttt{cmpX src2, src1} instruction (with X again any of the size postfixes),
that essentially computes $(a - b)$ without setting a destination register.
When we execute that instruction, \texttt{CF} is set if \texttt{a < b} (unsigned), \texttt{ZF} is set if \texttt{a == b}, \texttt{SF} is set if \texttt{a < b} (signed)
and \texttt{OF} is set as above, where \texttt{t = a - b}.
Another instruction that is used is \texttt{testX src2, src1} (X again a size postfix), and acts like computing \texttt{a \& b} and where \texttt{ZF} is set if \texttt{a \& b == 0}
and \texttt{SF} is set if \texttt{a \& b < 0}.
\content{Zeroing register} We can use a move instruction, but that is less efficient than using \texttt{xorl reg, reg}, where \texttt{reg} is the 32-bit version of the reg we want to zero.
\content{Reading condition codes} To read condition codes, we can use the \texttt{setC} instructions, where the \texttt{C} is to be substituted by an element of table \ref{tab:condition-codes}
\content{Jumping} To jump, we have the \texttt{jmp <label>} instruction (unconditional jump) or the \texttt{jC} instructions, with \texttt{C} from table \ref{tab:condition-codes}
\begin{table}[h!]
\begin{tables}{lll}{\texttt{setX} & Condition & Description}
\texttt{e} & \verb|ZF| & Equal / Zero \\
\texttt{ne} & \verb+~ZF+ & Not Equal / Not Zero \\
\texttt{s} & \verb|SF| & Negative \\
\texttt{ns} & \verb+~SF+ & Nonnegative \\
\texttt{g} & \verb+~(SF^OF)&~ZF+ & Greater (signed) \\
\texttt{ge} & \verb+~(SF^OF)+ & Greater or equal (signed) \\
\texttt{l} & \verb+SF^OF+ & Less (signed) \\
\texttt{le} & \verb+(SF^OF)|ZF+ & Less or equal (signed) \\
\texttt{a} & \verb+~CF&~ZF+ & Above (unsigned) \\
\texttt{b} & \verb|CF| & Below (unsigned) \\
\end{tables}
\caption{Condition code postfixes for jump and set instructions}
\label{tab:condition-codes}
\end{table}
\content{Conditional Moves}
Similar to \texttt{jC}, the same postfixes can be applied to \texttt{cmovC}, for example:
\begin{minted}{gas}
cmpl %eax, %edx
cmovle %edx, %eax
\end{minted}
Will move \verb|%edx| into \verb|%eax|, only if \verb|%edx| is less or equal (\verb|le|) \verb|%eax|.
This can be used to, for example, compile ternary expressions from \verb|C| to Assembly. However, this requires evaluating both possible expressions, which may lead to a (significant) performance overhead.

View File

@@ -0,0 +1,9 @@
\newpage
\subsection{Operations}
Assembly operations include performing arithmetic or logic functions on registers or memory data,
transferring data between memory and registers and transferring control (conditional or unconditional jumps).\\
Note that \verb|move| instructions \textit{cannot} move data directly from memory to memory.
The following instruction formats are commonly used:
\inputcodewithfilename{gas}{code-examples/01_asm/}{00_operations.s}

View File

@@ -0,0 +1,17 @@
\subsubsection{Arithmetic Operations}
Arithmetic / logic operations need a size postfix (replace \texttt{X} below with \texttt{b} (1B), \texttt{w} (2B), \texttt{l} (4B) or \texttt{q} (8B)).
\begin{tables}{lll}{Mnemonic & Format & Computation}
\texttt{addX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest + Src} \\
\texttt{subX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest - Src} \\
\texttt{imulX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest * Src} \\
\texttt{salX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest << Src} \\
\texttt{sarX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest >> Src} (arithmetic) \\
\texttt{shrX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest >> Src} (logical) \\
\texttt{xorX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest \string^ Src} \\
\texttt{andX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest \& Src} \\
\texttt{orX} & \texttt{Src, Dest} & \texttt{Dest} $\gets$ \texttt{Dest | Src} \\
\texttt{incX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{Dest + 1} \\
\texttt{decX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{Dest - 1} \\
\texttt{negX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{-Dest} \\
\texttt{notX} & \texttt{Dest} & \texttt{Dest} $\gets$ \texttt{\string~Dest} \\
\end{tables}

View File

@@ -0,0 +1,24 @@
\subsubsection{Condition Codes}
Any arithmetic operation (that is truly part of the arithmetic operations group, so not including \texttt{lea} for example) implicitly sets the \bi{condition codes}.
The following condition codes were covered in the lecture (operation: \texttt{t = a + b}):
\begin{itemize}
\item \texttt{CF} (Carry Flag): Set if carry out from MSB (unsigned overflow)
\item \texttt{ZF} (Zero Flag): Set if \texttt{t == 0}
\item \texttt{SF} (Sign Flag): Set if \texttt{(a - b) < 0} (for signed)
\item \texttt{OF} (Overflow Flag): Set if two's complement overflow (i.e. \verb+(a>0 && b>0 && t<0) || (a<0 && b<0 && t>=0)+)
\end{itemize}
\content{Explicit computation}
In the below explanations, we always assume \texttt{src2 = b} and \texttt{src1 = a}
To explicitly compute them, we can use the \texttt{cmpX src2, src1} instruction (with X again any of the size postfixes),
that essentially computes $(a - b)$ without setting a destination register.
When we execute that instruction, \texttt{CF} is set if \texttt{a < b} (unsigned), \texttt{ZF} is set if \texttt{a == b}, \texttt{SF} is set if \texttt{a < b} (signed)
and \texttt{OF} is set as above, where \texttt{t = a - b}.
Another instruction that is used is \texttt{testX src2, src1} (X again a size postfix), and acts like computing \texttt{a \& b} and where \texttt{ZF} is set if \texttt{a \& b == 0}
and \texttt{SF} is set if \texttt{a \& b < 0}.
\content{Zeroing register} We can use a move instruction, but that is less efficient than using \texttt{xorl reg, reg}, where \texttt{reg} is the 32-bit version of the reg we want to zero.
\content{Reading condition codes} To read condition codes, we can use the \texttt{setC} instructions, where the \texttt{C} is to be substituted by an element of table \ref{tab:condition-codes}

View File

@@ -0,0 +1,33 @@
\subsubsection{Jumping}
To jump, use \texttt{jmp <label>} (unconditional jump) or the \texttt{jC} instructions, with \texttt{C} from table \ref{tab:condition-codes}
\begin{table}[h!]
\begin{tables}{lll}{\texttt{setX} & Condition & Description}
\texttt{e} & \verb|ZF| & Equal / Zero \\
\texttt{ne} & \verb+~ZF+ & Not Equal / Not Zero \\
\texttt{s} & \verb|SF| & Negative \\
\texttt{ns} & \verb+~SF+ & Nonnegative \\
\texttt{g} & \verb+~(SF^OF)&~ZF+ & Greater (signed) \\
\texttt{ge} & \verb+~(SF^OF)+ & Greater or equal (signed) \\
\texttt{l} & \verb+SF^OF+ & Less (signed) \\
\texttt{le} & \verb+(SF^OF)|ZF+ & Less or equal (signed) \\
\texttt{a} & \verb+~CF&~ZF+ & Above (unsigned) \\
\texttt{b} & \verb|CF| & Below (unsigned) \\
\end{tables}
\caption{Condition code postfixes for jump and set instructions}
\label{tab:condition-codes}
\end{table}
\content{Conditional Moves}
Similar to \texttt{jC}, the same postfixes can be applied to \texttt{cmovC}, for example:
\begin{minted}{gas}
cmpl %eax, %edx
cmovle %edx, %eax
\end{minted}
Will move \verb|%edx| into \verb|%eax|, only if \verb|%edx| is less or equal (\verb|le|) \verb|%eax|.
This can be used to, for example, compile ternary expressions from \verb|C| to Assembly.
However, this requires evaluating both possible expressions, which may lead to a (significant) performance overhead.

View File

@@ -35,5 +35,5 @@ The same function, using a \verb|while| loop instead may lead to this:
Sparse switch statements are compiled as decision trees, whereas large switch statements may become \textit{jump tables}.
These jump tables are usually stored in the \texttt{.rodata} section with 8-byte alignment. The jump uses offsets:
\mint{asm}|jmp *.LABEL(, %rsi, 8)|
\mint{gas}|jmp *.LABEL(, %rsi, 8)|
and we jump to the effective address of \texttt{.LABEL + rsi * 8}

View File

@@ -4,7 +4,7 @@ In the below two, we can do this with $x = 1, 2, 4, 8$, each corresponding to a
\bi{Stack push} \texttt{pushX src}: Fetch operand at \texttt{src}, decrement \texttt{\%rsp} by $x$, then writes the operand at address of \texttt{\%rsp}
\bi{Stack pop} \texttt{popX dest}: Does the opposite, reads operand at \texttt{\%rsp}, increments it by $x$, then writes the operand into \texttt{dest}
\bi{Stack pop} \texttt{popX dest}: Fetch operand at address of \texttt{\%rsp}, increment \texttt{\%rsp} by $x$, then writes the operand into \texttt{dest}
\content{Procedure call / return} Use \texttt{call LABEL}. This pushes return label to the stack and jumps to the LABEL.
After this instruction, we also may use the \texttt{pushX} instruction to store further registers.
@@ -49,4 +49,4 @@ If we can do all accesses to the stack relative to the stack pointer, we do not
update \texttt{\%rbp} and not even \texttt{\%rbx}, or we can use it for other purposes.
We can also allocate the entire stack frame immediately by incrementing the stack pointer to the final position and then store data relative to it.
To deallocate a stack frame, simply increment the stack pointer
To deallocate a stack frame, simply increment the stack pointer.

View File

@@ -0,0 +1,6 @@
\newpage
\subsection{Variadic functions}
Variadic functions take a variable number of arguments and use the \texttt{...} syntax in \lC.
A notable example of such a function is \texttt{printf}
\inputcodewithfilename{c}{code-examples/00_c/03_others/}{00_variadic.c}