INF1070 Løsningsforslag oppgaver uke 9 (26.2.-2.3.2007) Oppgave 1 void swap (int *a, int *b) { int temp = *a; *a = *b; *b = temp; } Oppgave 2 Det er mange måter å bytte om to variable på. Her hadde det vært fint å kunne skrive xchgl (%eax),(%ecx) men den instruksjonen finnes ikke! Å bruke push og pop er enkelt å skrive og lett å forstå, så jeg valgte den teknikken. (Men det er mulig å klare det med tre instruksjoner om man bruker xchgl.) .globl swap # Navn: swap. # Synopsis: Bytter om to variable. # C-signatur: void swap (int *a, int *b). swap: push %ebp # Standard funksjonsstart movl %esp,%ebp movl 8(%ebp),%eax # %eax = a. movl 12(%ebp),%ecx # %ecx = b. # Bytt om *a og *b: push (%eax) # push *a. push (%ecx) # push *b. pop (%eax) # pop *a. pop (%ecx) # pop *b. pop %ebp # Standard retur ret Oppgave 3 void strrev (char *s) { char *t = s + strlen(s)-1; while (s < t) { char temp = *s; *s = *t; *t = temp; ++s; --t; } } Oppgave 4 Siden char er på bare 1 byte, må vi bruke movb for å jobbe med tegnene. Derfor fungerer heller ikke push-og-pop-metoden fra oppgave 2 her (hvorfor ikke?); vi bruker i stedet to ledige registre: %cl og %ch. Det er også en hjelp å dele problemet i to: 1. Finn slutten av teksten. 2. Bytt om tegnene. .globl strrev # Navn: strrev. # Synopsis: Snur en tekst. # C-signatur: void strrev (char *s). strrev: push %ebp # Standard funksjonsstart movl %esp,%ebp movl 8(%ebp),%eax # %eax = s. movl %eax,%edx # %eax = s. # Finn slutten av teksten: scan: cmpb $0,(%edx) # while (*s jz found # != 0) { incl %edx # ++s. jmp scan # } found: decl %edx # --s. # Snu teksten: rev: cmpl %eax,%edx # while (s < t jbe ret # ) { movb (%eax),%cl # Bytt *s movb (%edx),%ch # og *t (med %cl og movb %ch,(%eax) # %ch som mellomlager). movb %cl,(%edx) # incl %eax # ++s. decl %edx # --t. jmp rev # } ret: pop %ebp # Standard retur. ret Oppgave 5 .globl summany # Navn: summany. # Synopsis: Summerer diverse heltall. Verdien 0 svalutter. # C-signatur: int summany (int a, ...). # Registre: %eax: sum (resultatet) # %edx: sp (peker til parametrene på stakken) summany: push %ebp # Standard funksjonsstart movl %esp,%ebp movl $0,%eax # sum = 0. movl %ebp,%edx # sp = %adx addl $8,%edx # +8. (Første parameter) # while ( loop: cmpl $0,(%edx) # *sp jz ret # != 0) { addl (%edx),%eax # sum += *sp. addl $4,%edx # sp = sp+4. (Neste parameter) jmp loop # } ret: pop %ebp # Standard retur. ret Oppgave 6 I denne funksjonen trenger jeg flere registre enn de tre frie (%eax, %ecx og %edx). Derfor gjemmer jeg %esi på stakken; da kan jeg bruke %esi -- jeg må bare huske å hente det tilbake når funksjonen er ferdig. Jeg har behov for å konvertere et 8-bits tall (uten fortegn) til 32-bit. Dette ordnes enklest ved å nulle ut alle bit-ene først; de øvre 24 bit-ene skal jo bli 0 uansett. For å unngå sammenblanding med standardfunksjonen `atoi´ har jeg kalt min versjon `atoi2´. .globl atoi2 # Navn: atoi2. # Synopsis: Dekoder en tekst til tallverdien der. # C-signatur: int atoi2 (char *s) # Registre: %eax: res (resultatet) # %ecx: c (hvert tegn) # %edx: 10 (en konstant) # %esi sp (peker til tegnene i teksten) atoi2: push %ebp # Standard funksjonsstart movl %esp,%ebp push %esi # Gjem unna %esi movl 8(%ebp),%esi # sp = s. movl $0,%eax # res = 0. # while ( loop: movl $0,%ecx # /* Null ut %ecx før movb (se over). */ movb (%esi),%cl # (c = *sp subb $48,%cl # - '0') js ret # >=0) { movl $10,%edx # 10. mull %edx # res = res* addl %ecx,%eax # res += c. incl %esi # ++sp. jmp loop # } ret: pop %esi # Hent tilbake %esi. pop %ebp # Standard retur. ret