7 A longer example
Here is a long(er) example to illustrate the concepts introduced in this module. To make the “diff” between revisions stand
out more, you can copy-and-paste each section of code into files. Then, use vimdiff or a similar visualized diff command to
have the changes highlighted. If you have XWindow running, there is a whole list of these tools: tkdiff, xxdiff, diffuse,
gvimdiff, etc.
Let’s say we want to convert the following code into assembly code:
int x,y,z;
int main(
void)
{ x = 5;
z = 0;
while (x
> 0)
{ y = 0;
while (y
< 5)
{ if (((x
> 2) && (x != y))
|| (y == 1))
{ z = z + x;
} } } }
This program no particular “meaning” as in useful behavior, its only purpose is to serve as an example.
First, I can comment out the entire program, and start to work on it little-by-little. This can be done with a single
command in vi, there is a reason to learn how to use it!
# int x,y,z;
# int main(
void)
# { # x = 5;
# z = 0;
# while (x
> 0)
# { # y = 0;
# while (y
< 5)
# { # if (((x
> 2) && (x != y))
|| (y == 1))
# { # z = z + x;
# } # } # } # }
Next, let us divide the data portion from the code portion. We can also insert the program template to start and
exit.
# int x,y,z;
.data
x: .
int 0
y: .
int 0
z: .
int 0
.text
.global _start
# int main(
void)
_start:
# { # x = 5;
# z = 0;
# while (x
> 0)
# { # y = 0;
# while (y
< 5)
# { # if (((x
> 2) && (x != y))
|| (y == 1))
# { # z = z + x;
# } # } # } # } movl
$1,%eax
movl
$0,%ebx
int $0x80
The initialization portion is also quite easy.
# int x,y,z;
.data
x: .
int 0
y: .
int 0
z: .
int 0
.text
.global _start
# int main(
void)
_start:
# { # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
# { # y = 0;
movl
$0,y
# while (y
< 5)
# { # if (((x
> 2) && (x != y))
|| (y == 1))
# { # z = z + x;
# } # } # } # } movl
$1,%eax
movl
$0,%ebx
int $0x80
Adding x to z requires an intermediate register, but otherwise it is also straightforward.
# int x,y,z;
.data
x: .
int 0
y: .
int 0
z: .
int 0
.text
.global _start
# int main(
void)
_start:
# { # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
# { # y = 0;
movl
$0,y
# while (y
< 5)
# { # if (((x
> 2) && (x != y))
|| (y == 1))
# { # z = z + x;
movl x,%eax
addl %eax,z
# } # } # } # } movl
$1,%eax
movl
$0,%ebx
int $0x80
Now let us take care of the inner-most conditional statement. First, we reduce to “ugly” conditional statement
code:
# int x,y,z;
.data
x: .
int 0
y: .
int 0
z: .
int 0
.text
.global _start
# int main(
void)
_start:
# { # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
# { # y = 0;
movl
$0,y
# while (y
< 5)
# { # // if (((x > 2) && (x != y)) || (y == 1)) # if (!(((x
> 2) && (x != y))
|| (y == 1)))
goto endIf1
# { # z = z + x;
movl x,%eax
addl %eax,z
# } # endIf1:
# } # } # } movl
$1,%eax
movl
$0,%ebx
int $0x80
DeMorgan’s law allows us to simplify the negated disjunction a little. DeMorgan’s law says X + Y = X ⋅Y . Then,
we can optimize a negation out by using a different comparison operator. As a result, we have the following
code:
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# while (y
< 5)
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} # endIf1:
#
} #
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
Now is a good time to take care of the conjunction. We can reduce the conjunction by converting the conditional-goto
into multiple statements:
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# while (y
< 5)
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# if ((x
> 2) && (x != y)) goto if1_1;
# if (y != 1) goto endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} # endIf1:
#
} #
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
We can now take care of the simple transformations:
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# while (y
< 5)
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# if ((x
> 2) && (x != y)) goto if1_1;
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} #
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
Now we translate the other conjunction.
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# while (y
< 5)
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# // if ((x
> 2) && (x != y)) goto if1_1;
# if (x
<= 2) goto if1_2;
# if (x != y) goto if1_1;
if1_2:
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} #
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
Then we turn the conditional goto into native assembly language code:
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# while (y
< 5)
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# // if ((x
> 2) && (x != y)) goto if1_1;
# // if (x
<= 2) goto if1_2;
cmpl
$2,x
jng if1_2
# // if (x != y) goto if1_1;
movl y,%eax
cmpl %eax,x
jnz if1_1
if1_2:
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} #
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
Now is a good time to test the code with different combinations of values for the variables. Once the conditional
statement is checked, we can work on the inner loop.
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# // while (y
< 5)
# if (y
>= 5) goto endWhile1
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# // if ((x
> 2) && (x != y)) goto if1_1;
# // if (x
<= 2) goto if1_2;
cmpl
$2,x
jng if1_2
# // if (x != y) goto if1_1;
movl y,%eax
cmpl %eax,x
jnz if1_1
if1_2:
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} endWhile1:
#
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
Note the use of indentation makes it (relatively) easy to locate the beginning and the end of the inner while loop. Next,
we translate the inner loop to assembly code:
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# while (x
> 0)
#
{ # y = 0;
movl
$0,y
# // while (y
< 5)
# // if (y
>= 5) goto endWhile1
cmpl
$5,y
jnl endWhile1
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# // if ((x
> 2) && (x != y)) goto if1_1;
# // if (x
<= 2) goto if1_2;
cmpl
$2,x
jng if1_2
# // if (x != y) goto if1_1;
movl y,%eax
cmpl %eax,x
jnz if1_1
if1_2:
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} endWhile1:
#
} #
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
This is a good time to test the inner loop. Once the inner loop is tested (to a certain extent), it is time to complete the
outer loop. I am combining all the steps, as it gets boring after a while!
# int x,y,z;
.data
x: .int 0
y: .int 0
z: .int 0
.text
.global _start
# int main(void)
_start:
#
{ # x = 5;
movl
$5,x
# z = 0;
movl
$0,z
# // while (x
> 0)
# // if (x
<= 0) goto endWhile2
cmpl
$0,x
jng endWhile2
#
{ # y = 0;
movl
$0,y
# // while (y
< 5)
# // if (y
>= 5) goto endWhile1
cmpl
$5,y
jnl endWhile1
#
{ # // if (((x
> 2) && (x != y))
|| (y == 1))
# // if (!(((x
> 2) && (x != y))
|| (y == 1))) goto endIf1
# // if (!((x
> 2) && (x != y)) && (y != 1)) goto endIf1
# // if ((x
> 2) && (x != y)) goto if1_1;
# // if (x
<= 2) goto if1_2;
cmpl
$2,x
jng if1_2
# // if (x != y) goto if1_1;
movl y,%eax
cmpl %eax,x
jnz if1_1
if1_2:
# // if (y != 1) goto endIf1
cmpl
$1,y
jnz endIf1
if1_1:
#
{ # z = z + x;
movl x,%eax
addl %eax,z
#
} endIf1:
#
} endWhile1:
#
} endWhile2:
#
} movl
$1,%eax
movl
$0,%ebx
int
$0x80
And that’s it!