ASM Archives - Technik - Blogbasis.net https://technik.blogbasis.net/tag/asm Die Basis des freien Wissens – Technik Tue, 21 May 2013 18:22:59 +0000 de hourly 1 https://wordpress.org/?v=6.8.1 Schleifen in MIPS Assembler umsetzen https://technik.blogbasis.net/schleifen-in-mips-assembler-umsetzen-21-05-2013 https://technik.blogbasis.net/schleifen-in-mips-assembler-umsetzen-21-05-2013#respond Tue, 21 May 2013 18:22:46 +0000 http://technik.blogbasis.net/?p=545 In diesem Artikel soll es um die verschiedenen Schleifentypen und deren Umsetzung in MIPS Assembler gehen. Die Schleifen sehen in Assembler alle relativ gleich aus.

Für jeden Schleifentyp werde ich einen kleinen C-Code angeben, und diesen daraufhin in MIPS Assembler übersetzen.

For Schleife

Die wohl am weitesten verbreitete Schleife ist die sog. For-Schleife. Diese wird oft genutzt, um n-mal einen Befehlsblock auszuführen.

C-Code:

int i;
for(i = 0; i < 10; i++) {
//Mach was 10 mal
}

Wenn wir diese Schleife in MIPS Assembler übersetzen wollen, können wir das wie folgt tun:

MIPS ASM:

add $t0, $zero, $zero #$t0 = i = 0
addi $t1, $zero, 10 #$t1 = 10
for:
    bge $t0, $t1, endfor # IF ($t0 >= $t1) GOTO endfor
    #Befehle
    addi $t0, $t0, 1 #i++
    j for #GOTO for
endfor:
    #Weiter gehts

Wir müssen zunächst in zwei temporären Registern den Startwert von i bzw. die obere Grenze (10) festlegen. Als nächstes benötigen wir zwei Labels (for, endfor) zu denen wir springen können. In der For-Schleife prüfen wir zunächst, ob der Zähler größer gleich 10 ist. Ist dies der Fall, dann springen wir aus der Schleife zum Label „endfor“. Andernfalls werden die Befehle in der Schleife ausgeführt, und der Zähler inkrementiert, sowie wieder zum „for“-Label gesprungen.

While-Schleife

Mit einer While-Schleife kann man Befehle solange ausführen, bis eine bestimmte Abbruchbedingung eingetreten ist.

C-Code:

int sum = 0
while(sum < 20) {
sum = sum*2;
}

MIPS ASM:

add $t0, $zero, $zero #$t0 = sum = 0
addi $t1, $zero, 20 #$t1 = 20
while:
    bge $t0, $t1, endwhile #IF($t0 >= $t1) GOTO endwhile
    mult $t0, $t0, 2 #$t0 = $t0 * 2
    j while #GOTO while
endwhile:
#Weitere Befehle

Wie man hier erkennt, gibt es keinen großen Unterschied zur For-Schleife, außer das der Schleifenrumpf anderen Code enthält.

Repeat until bzw. Do while Schleifen

Bei diesem Schleifentyp wird die Prüfung des Schleifenkopfes am Ende des Schleifendurchlaufs ausgeführt, sodass die Schleife mindestens einmal durchlaufen wird. Dies können wir im Assembler  erreichen, in dem wir die „branch“-Anweisung nach dem Schleifenrumpf auswerten.

Fazit

In Assembler lassen sich Schleifen sehr leicht umsetzen, da sie immer auf dem gleichen Schema basieren, und es kaum Unterschiede zwischen diesen gibt.

~ Sebastian

]]>
https://technik.blogbasis.net/schleifen-in-mips-assembler-umsetzen-21-05-2013/feed 0
MIPS Cross-Compiler einrichten https://technik.blogbasis.net/mips-cross-compiler-einrichten-24-04-2013 https://technik.blogbasis.net/mips-cross-compiler-einrichten-24-04-2013#respond Wed, 24 Apr 2013 18:00:17 +0000 http://technik.blogbasis.net/?p=462 Ich hatte vor einigen Tagen einen Artikel über den MIPS Assembler geschrieben. Ich habe seit der letzten Woche dazu eine Hausaufgabe aufbekommen, in der steht, man solle den C Code in MIPS Assembler umschreiben, sodass das Ergebnis 1:1 wie Compilerproduziert aussieht.

Da ich dieses Anspruch für etwas utopisch halte, habe ich mir fix einen MIPS Cross-Compiler zugelegt, um die beiden Quelltexte zu vergleichen.

Installation des MIPS Cross-Compilers

Diesmal hatte ich nicht viel Lust mir die ganzen Pakete vom Source zu kompilieren, und habe auf die vorkompilierten Pakete zurückgegriffen. Diese können wir uns ganz einfach ins /opt Verzeichnis herunterladen und dort entpacken.

cd /opt
sudo mkdir mips-gcc
cd mips-gcc
sudo wget http://d2gosfejro2q5l.cloudfront.net/Mips_linux_toolchain_bin-1.1.tar.bz2
sudo tar xfvj Mips_linux_toolchain_bin-1.1.tar.bz2

Damit ist die Installation fast schon getan. Wenn wir den Cross-Compiler nutzen möchten, müssen wir noch die PATH-Variable anpassen. Das klappt einfach mit einem export:

export PATH="$PATH:/opt/mips-gcc/mips_linux_toolchain/bin"

MIPS Cross-Compiler nutzen

Wenn wir den von uns geschriebenen Assemblercode mit dem des Compilers vergleichen wollen, müssen wir erstmal den zu übersetzenden Code in C implementieren. Ein kleines Beispiel dafür wäre dieser Code:

int add(int a, int b);
int main(char **args) {
    (void) add(1,2);
}
int add(int a, int b) {
    return a+b;
}

Wenn wir diesen Quelltext abspeichern und danach den mips-linux-gnu-gcc aufrufen, haben wir die Binary, welche auf einem MIPS laufen würde.

mips-linux-gnu-gcc code.c -o code 

Die Binary decompilen

Möchten wir wieder an den Assemblercode gelangen, so nutzen wir einfach das Tool namens objdump:

mips-linux-gnu-objdump -d code > code.asm

Wenn man nun die .asm mit einem Editor öffnet, findet man darin unsere „add“ Funktion:

004005ac : <add>:
  4005ac:       27bdfff8        addiu   sp,sp,-8
  4005b0:       afbe0004        sw      s8,4(sp)
  4005b4:       03a0f021        move    s8,sp
  4005b8:       afc40008        sw      a0,8(s8)
  4005bc:       afc5000c        sw      a1,12(s8)
  4005c0:       8fc30008        lw      v1,8(s8)
  4005c4:       8fc2000c        lw      v0,12(s8)
  4005c8:       00621021        addu    v0,v1,v0
  4005cc:       03c0e821        move    sp,s8
  4005d0:       8fbe0004        lw      s8,4(sp)
  4005d4:       27bd0008        addiu   sp,sp,8
  4005d8:       03e00008        jr      ra
  4005dc:       00000000        nop

Wie wir sehen, macht der Compiler kräftigen Gebrauch vom Stack. Wir können hingegen ein viel kürzeres Programm schreiben. Folgende Zeilen beinhalten das komplette Programm inklusive der zweizeiligen Add (hier umbenannt, da sonst der Simulator meckert) Funktion:

.data
aa:  .word   1
bb:  .word   2

.text
main:
    lw $a0, aa  #Variable a ins $a0 laden
    lw $a1, bb  #Variable b ins $a1 laden
    jal ownadd     #Add aufrufen
    j exit      #Beenden

ownadd:
    add $v0, $a0, $a1   #a+b rechnen und ins $v0 ablegen
    jr $ra              #Zurückspringen

exit:
    li $v0, 10          #Exitcode
    syscall

Fazit

Ich denke die Forderung, einen Code 1:1 wie vom Compiler zu schreiben ist bzw. war übertrieben oder nicht so gemeint. Trotzdem ist es interessant zu sehen, welche Unterschiede zwischen dem Compiler generierten Code und dem selbst geschriebenen Code entstehen können.

~ Sebastian

]]>
https://technik.blogbasis.net/mips-cross-compiler-einrichten-24-04-2013/feed 0