Lab 3 (the very beginning)
Hello
again,
This time I started to program in assembly. I’ve have heard before
that programming in assembly is a thing to crazy guys, but everyone
that start to program is a little crazy, isn’t it? So let’s begin
and see how crazy we can be. To start, my professor has give me some
“hello world” code, some material to study and an example of loop
in x86_64 assembly. As I never had a Linux class and everything that
I learn of Linux was googling my needs (I’m a exchange student,
doing the program for only a semester), I follow the tip of my
professor to use vi program, because it’s already installed in
every Linux machine and it would give me less headache. So, I used
“vi loop.s” command and paste the loop example:
.text
.globl _start
start = 0 /* starting value for the loop index; note that this is a
symbol (constant), not a variable */
max = 10 /* loop exits when the index hits this number (loop
condition is i<max) */
_start:
mov $start,%r15 /* loop index */
loop:
/* ... body of the loop ... do something useful here ... */
inc %r15 /* increment index */
cmp $max,%r15 /* see if we're done */
jne loop /* loop if we're not */
mov $0,%rdi /* exit status */
mov $60,%rax /* syscall sys_exit */
syscall
Obs.: The “vi file.extension” open the file in vi program, if the
file does not exist, it creates one.
Obs.2: You have to type i to enter insert mode in vi, so you can
paste the code.
Obs.3: Paste the code with ctrl+shift+v, not ctrl+v (same to copy
code, use shift as well) in the terminal (if you can use a text
editor separately from the terminal, luck of you, I couldn’t, so
use the one you wish).
Obs.4: To save, press Esc to exit insert mode and then type :wq. When
you press enter this will exit and save what you typed.
Obs.5: As I said, this is a x86_64 architecture code, so be sure that
this is the architecture of your machine, if it’s not, I’ll do a
aarch64 code too, but pay attention in this explanation because I
won’t repeat some things. I won’t separate x86_64 and aarch64 in
more visible sections, so you’ll not jump to aarch64 and lost
knowledge (no, it’s not because I’m lazy).
Obs.6: This was a group activity, my group wrote a beautiful code
that a vaguely understand, but I tried to save it and take a look in
home. Well, I tried. I tried and failed. I couldn’t find it, so my
code will be uglier than my group one.
So, with the base code, we’ll start to write the modifications,
right? Wrong. First we have to test if something goes wrong in “my”
code that does nothing (it’s better do nothing than give us a error
message, right?). So, to be faster, I’ve wrote a Makefile (vi
Makefile) as follow:
loop: loop.s
as -g -o loop.o loop.s
ld -o loop loop.o
Obs.7: Use tab, not space, it could give you some errors.
After write this, I had only to use make command and then, execute
(./loop). And (after I fixed some mistakes that I have done, as tried
to compile as x86, not x86_64) nothing successfully happens, =D! Now
what? Let’s modify our code to write something, but what? A loop of
course, a loop that goes from 0 to 9. How? I looked in my professor
Hello world example and saw how to add data on the code. After the
code I wrote in loop.s I added this:
.section .rodata
msg: .ascii "Hello, world!\n"
len = . - msg
Where I’m creating a variable (or something like that), it’s a
string (ascii format) and saying that len will take the length of it.
With my message, I had to show it, so I copy another part of the code
that shows the message to the user and replace the comment in the
loop (/* ... body of the loop ... do something useful here ... */):
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
I modified the msg to “Loop\n” instead "Hello, world!\n",
used make command, then ./loop command and I get ten “Loop”
messages in response. Now, how to show number? This part take me some
hours of research as I didn’t understand the professor tips very
well. First, as you will modify your data, change the .rodata
(read-only data) section name to .data. Then, change message to
“Loop: \n” (there is two spaces, the second space will be
replaced by the number). Now, as you’ve created a variable len,
you’ll create another two, I’ll call it d (digit) and l (line
feed or \n). d will receive the pointer of the second space (d = msg
+ 6) and l the pointer of \n (l = msg + 7), \n counts as one
character. Our section will be like this:
.section .data
msg: .ascii "Loop: \n"
len = . - msg /* message length */
d = msg + 6 /* position of second space */
l = msg + 7 /* position of line feed */
At _start, I initialize registers to replace d and l (the values
can’t directly replace d and l, they have to be in registers
first), %r8 I initialize with $48 (mov $48,%r8), remember that 48 is
0 in ascii, and %r9 I initialize with $10 (mov $10,%r9), 10 is the
line feed or \n in ascii:
_start:
mov $start,%r15 /* loop index */
mov $48,%r8 /* initialize register with 0 */
mov $10,%r9 /* initialize register with line feed */
Now I only had to replace the d value with the value of %r8
(mov %r8,d) and l with %r9 (mov %r9,l) before the code that shows the
message:
mov %r8,d /* replace d with %r8 value */
mov %r9,l /* replace l with %r9 value */
So, the message would show “Loop: 0”, now we just have to
increment the number after each output (inc %r8). The whole code will
seem like this:
.text
.globl _start
start = 0 /* starting value for the loop index; note that this is
a symbol (constant), not a variable */
max = 10 /* loop exits when the index hits this number (loop
condition is i<max) */
_start:
mov $start,%r15 /* loop index */
mov $48,%r8 /* initialize register with 0 */
mov $10,%r9 /* initialize register with line feed */
loop:
mov %r8,d /* replace d with %r8 value */
mov %r9,l /* replace l with %r9 value */
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
inc %r8 /* increment number */
inc %r15 /* increment index */
cmp $max,%r15 /* see if we're done */
jne loop /* loop if we're not */
mov $0,%rdi /* exit status */
mov $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Loop: \n"
len = . - msg /* message length */
d = msg + 6 /* position of second space */
l = msg + 7 /* position of line feed */
Obs.8: We can’t only change the msg + 6 position, so we’ll still
have the \n? No, when we modify this position it deletes everything
after it, so we have to modify the msg + 7 position to have the \n
again.
Obs.9: Can’t we have only “Loop: ”? No, because the length will
be less than it needs, so if you try to modify msg + 6 you’ll
access invalid memory and the program will probably not execute or
broke (I haven’t tested, but feel free to try if you want, =D).
Obs.10: Blogger erase all my tabs, but I'll post my codes with links when I finish.
Have we finish? Haha. We’re not even in the half. Now our loop has
to go until 30. But as this post seems to be very big, I’ll finish
for now and post the rest later.
Comentários
Postar um comentário