The assembly language our compiler generates is hypothetical assembly language, based on x86 assembly language, but simplified for learning purposes. We turned our attention away from system interrupts and varying register lengths and focused on basic instruction set which includes data tranfer, control flow, arithmetic, shift and logical instructions.
An instruction is a statement that is executed at runtime. A hypo-asm instruction statement can consist of three parts:
MOV src, dest | copies the source (src) operand to destination (dest) operand |
LEA src, dest | calculates the address of the src operand and loads it into the dest operand |
PUSH src | copies the src to the top of the stack |
POP dest | copies a value from the top of the stack to the dest |
CMP arg1, arg2 | subtracts the arg2 from the arg1 and sets flag bits |
JEQ label | jumps to the address specified by the label if operands of previous CMP instruction are equal (ZF = 1) |
JNE label | jumps if operands are not equal (ZF = 0) |
JLE label | jumps if arg1 is lower or equal than arg2 (ZF = 1 or SF different from OF |
JGE label | jumps if arg1 is greater or equal than arg2 (SF equal to OF) |
JLT label | jumps if arg1 is lower than arg2 (SF different from OF) |
JGT label | jumps if arg1 is greater than arg2 (ZF = 0 and SF equal to OF) |
CALL label | pushes the address of the instruction to the stack and jumps to a location specified by the label |
RET | pops the stack into the instruction pointer |
ADD arg1, arg2, dest | sum of arg1 and arg2 is stored into the dest operand |
SUB arg1, arg2, dest | subtracts arg2 from arg1 and stores the result into the dest operand |
MUL arg1, arg2, dest | multiplies arg1 and arg2 and stores the result into the dest operand. Multiplication overflow is stored to 12th register |
DIV arg1, arg2, dest | divides arg1 with arg2 and stores the result into the dest operand. Remainder is stored to 12th register |
INC src | increments src |
DEC src | decrements src |
SHL arg1, arg2, dest | logically shifts arg1 to the left by arg2 bits and stores the result into the dest operand |
SHR arg1, arg2, dest | logically shifts arg1 to the right |
AND arg1, arg2, dest | logical bitwise AND between arg1 and arg2. The result is stored into the dest operand |
OR arg1, arg2, dest | Logical bitwise OR |
XOR arg1, arg2, dest | Logical bitwise exclusive OR |
NOT src | Logical bitwise inversion of src |
An instruction can have zero to three operands. Operands are separated by commas (,). For instructions with two operands, the first (lefthand) operand is the source operand, and the second (righthand) operand is the destination operand (that is, source->destination).
Operands can be immediate (that is, constant expressions that evaluate to an inline value), register (a value in the processor number registers), or memory (a value stored in memory). A label operand contains the address of the actual opcode. Label operands are specified without prefix. Only jump and call instructions can use label operands.
Immediate | are prefixed with a dollar sign $ |
MOV $1, %0 ADD $1, $2, %1 |
Store 1 into the reg 0 Add 1 and 2 and store 3 into the reg 1 |
Register | are prefixed with a percent sign % |
MOV %13, %0 MUL %0, $2, %0 |
Move the value from the function return reg into the reg 0 Multiply the value from reg 0 by 2 and store the result into the reg 0 |
Memory | are specified either by the name of a variable or by a
register that contains the address of a variable. Memory
references have the following syntax: variable name or offset(base)
|
MOV -4(%BP), %0 SHL x, $2, %0 MOV (%0), x |
Move the value from the location pointed by the Base Pointer reg minus four bytes into the reg 0 Shift the value from variable x to the left by two places and store the result into the reg 0 Move the value at the location pointed by the reg 0 into the variable x |
Label | are specified without any prefix or prefixed with an at sign @ |
JMP @if_exit CALL swap |
Jump to the instruction pointed by the @if_exit label Call a swap method |
The FLAGS register is the status register that contains the current state of the processor. This register is 5 bits wide.
Zero flag (ZF) | is used to check the result of an arithmetic operation, including bitwise logical instructions. It is set if an arithmetic result is zero, and reset otherwise |
Parity (PF) | indicates if the number of set bits is odd or even in the binary representation of the result of the last operation |
Sign (SF) | indicates whether the result of the last mathematical operation resulted in a value whose most significant bit was set |
Carry (CF) | indicates when an arithmetic carry or borrow has been generated out of the most significant bit position |
Overflow (OF) | indicates when an arithmetic overflow has occurred in an operation |