[ASM] "functieaanroep" leest stack niet?

Pagina: 1
Acties:

  • RSpliet
  • Registratie: Juni 2003
  • Laatst online: 27-11-2025
Okee, voor alle duidelijkheid, ik ben redelijk onbekend wat betreft assembly. Ook wegens gebrek aan goede tutorials (Intel IA-32 reference design boeken dan weer wel :)) moet ik dit mij voornamelijk aan de hand van codevoorbeelden aanleren. Dat is natuurlijk niet helemaal waar, de intel boeken zijn enorm informatief, maar bij gebrek aan deel 3 kom ik er toch niet helemaal uit.
Situatie:
ik heb de volgende code. Deels van OSDever (Bona Fide OS), deels zelf geprutst:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[BITS 16]      ; 16 bit code generation
[ORG 0x7C00]   ; Origin location

; Main program
main:       ; Label for the start of the main program

mov eax,0x0000  ; Setup the Data Segment register
        ; Location of data is DS:Offset
mov ds,eax  ; This can not be loaded directly it has to be in two steps.
        ; 'mov ds, 0x0000' will NOT work due to limitations on the CPU

mov esi, HelloWorld ; Load the string into position for the procedure.
push esi
call PutStr

sti     ; Do not disturb
hlt     ; or do anything else

PutStr:
 pop esi    ; retreive position of string
 .nextchar3
 lodsb      ; load next character of string into al
 or al,al
 ret
 push eax   ; cramming it onto the stack
 call PutChar   ; calling output function
 jmp .nextchar3 ; next char!

; Procedures
PutChar:        ; Procedure label/start
 ; Set up the registers for the interrupt call
 pop eax
 mov ah,0x0E    ; The function to display a character (teletype)
 mov bh,0x00    ; Page number
 mov bl,0x07    ; Normal text attribute
 int 0x10   ; Run the BIOS video interrupt 
 ret        ; Return to main program

; Data

HelloWorld db 'Hello World',13,10,0

; End Matter
times 510-($-$$) db 0   ; Fill the rest with zeros
dw 0xAA55       ; Boot loader signature


Dit kan ik compilen met NASM, en testen met bochs. Echter, dit werkt niet. Ik krijg geen output op mijn scherm. Waarom niet? Al sla je me dood!
Mijn vermoeden is dat er bij een 'call' wordt gewisseld van stack, waardoor het poppen niet lukt in de 'functies' zelf. Daarentegen stond in de intel boeken dat zolang er niet tussen security levels wordt geswitched, dat er dan niets met de stack pointer gebeurt bij een call. Waar ga ik dus de mist in?

Edit: Na wat testjes ben ik erachter dat PutStr inderdaad wordt aangeroepen. PutChar echter nooit. Het kan dus niet anders dan dat esi niet bevat wat ik in eerste instantie heb gepushed. Moet ik dan toch eerst de stack selecteren op de een of andere manier? En waar vind ik die stack dan?

[ Voor 15% gewijzigd door RSpliet op 10-06-2005 11:04 ]

Schaadt het niet, dan baat het niet


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

code:
1
2
 or al,al
 ret


Zou je niet returnen als de zero flag geset is, ipv altijd returnen?
(btw, het is assembly, de assembler is het programma dat je code compileert)

En denk je ook niet dat het handiger is om asm eerst in het algemeen een beetje te begrijpen, door wat DOS .com programmaatjes te maken die je makkelijk kunt controleren met een debugger, ipv meteen bootloaders te maken die totaal niet te debuggen zijn? :)

[ Voor 42% gewijzigd door .oisyn op 09-06-2005 19:56 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • RSpliet
  • Registratie: Juni 2003
  • Laatst online: 27-11-2025
.oisyn schreef op donderdag 09 juni 2005 @ 19:53:
code:
1
2
 or al,al
 ret


Zou je niet returnen als de zero flag geset is, ipv altijd returnen?
(btw, het is assembly, de assembler is het programma dat je code compileert)
Dat vind ik nou een heel goed idee :+
Het had dus toch weinig te maken met de stack, ik moet idd nog een hoop leren.
En denk je ook niet dat het handiger is om asm eerst in het algemeen een beetje te begrijpen, door wat DOS .com programmaatjes te maken die je makkelijk kunt controleren met een debugger, ipv meteen bootloaders te maken die totaal niet te debuggen zijn? :)
Vind ik een heel mooi plan, echter heb ik geen DOS :+ en vrees ik dat ik met allerlei DOS-specifieke rommel te maken krijg, waar ik later weer niet van snap waarom het niet werkt.

Edit voor de personen hieronder: nee, heb ik niet. Linux all the way ;)

edit:
Foei modjes, niet lezen ;)

[ Voor 8% gewijzigd door RSpliet op 10-06-2005 11:21 ]

Schaadt het niet, dan baat het niet


  • nIghtorius
  • Registratie: Juli 2002
  • Laatst online: 27-04 15:36

nIghtorius

Poef!

Als je Win2k/XP hebt probeer eens voor de grap

Start->Uitvoeren (Win+R)
CMD

en in de command line interface debug [enter] invoeren.

Ryzen 9 5900X @ 5.1Ghz | MPG B550 GAMING CARBON | 96GB DDR4-3200 | RTX 4070TI | 2TB + 1TB m.2 SSD | 3x 1TB HDD | 1x 2TB SATA SSD | 32" G3223Q (4K/144Hz)


  • Daos
  • Registratie: Oktober 2004
  • Niet online
Seven of Nine schreef op donderdag 09 juni 2005 @ 20:12:
...
Vind ik een heel mooi plan, echter heb ik geen DOS :+ en vrees ik dat ik met allerlei DOS-specifieke rommel te maken krijg, waar ik later weer niet van snap waarom het niet werkt.
Het enige dat DOS toevoegt is interrupt 0x21. Hier kan je veel standaard functies vinden om bestanden te openen, andere programma's te starten etc.

Voor DOS moet je beginnen met [ORG 0x100] en eindigen met "int 0x20" of met zoiets "mov ah, 0x4C; mov al, 0; int 0x21;"


Bijna alle DOS-programma's werken ook onder Windows.

edit:
nIghtorius schreef op donderdag 09 juni 2005 @ 20:18:
Als je Win2k/XP hebt probeer eens voor de grap

Start->Uitvoeren (Win+R)
CMD

en in de command line interface debug [enter] invoeren.
En dan zorgen dat er zoiets komt te staan (^C = Ctrl + C):
code:
1
2
3
4
5
6
7
8
9
C:\WINDOWS>debug
-a100
1766:0100 mov dx, 109
1766:0103 mov ah, 09
1766:0105 int 21
1766:0107 int 20
1766:0109 db "Hello World!", '$'
1766:0116 ^C
-g


linkjes:
goede tutorial
goed online boek

[ Voor 41% gewijzigd door Daos op 09-06-2005 21:22 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Seven of Nine schreef op donderdag 09 juni 2005 @ 20:12:
Vind ik een heel mooi plan, echter heb ik geen DOS :+ en vrees ik dat ik met allerlei DOS-specifieke rommel te maken krijg, waar ik later weer niet van snap waarom het niet werkt.
De winnt console is nog altijd grotendeels DOS compatible, dus dat zou geen probleem moeten zijn :)

[ Voor 12% gewijzigd door .oisyn op 10-06-2005 11:42 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • RSpliet
  • Registratie: Juni 2003
  • Laatst online: 27-11-2025
.oisyn schreef op vrijdag 10 juni 2005 @ 11:13:
[...]


De winnt console is nog altijd grotendeels DOS compatible, dus dat zou geen probleem moeten zijn :)
Moet ik je nu mailen, je bent vervelend :+

Maarehh, zoals ik hierboven al had aangegeven, ik gebruik dus geen Windows. Op deze bak uitsluitend Linux... En ik ga hier niet zitten devven op m'n pa's doosje.

[ Voor 7% gewijzigd door RSpliet op 10-06-2005 11:24 ]

Schaadt het niet, dan baat het niet


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dan installeer je DOS onder bochs? :P

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Daos
  • Registratie: Oktober 2004
  • Niet online
Onder Linux heb je AT&T-assembly (AT&T was grondlegger van Unix). In GCC kan je gewoon de C-functies gebruiken. Voorbeeld:

Als je dit in "hello.s" zet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        .section        .rodata
hello:
        .string "Hello World!\n"


        .text
.globl main
main:
        pushl   $hello
        call    puts
        addl    $4, %esp

        movl    $0, %eax

        ret

en vervolgens "gcc hello.s" aanroept, dan komt er een uitvoerbare "a.out".


Er zijn wat grote verschillen met NASM syntax. Sun heeft een goede handleiding op zijn site staan (link).

offtopic:
Voorbeeld doet ongeveer hetzelfde als:
C:
1
2
3
4
5
6
7
8
#include <stdio.h>

int main() {

  puts("Hello World!\n");

  return 0;
}


Waarom gebruik je geen C (of C++)? Het programmeren gaat daarin veel sneller en de code is overzichtelijker.

[ Voor 14% gewijzigd door Daos op 10-06-2005 16:32 . Reden: linkje naar Sun ]


  • Daos
  • Registratie: Oktober 2004
  • Niet online
1)
Seven of Nine schreef op donderdag 09 juni 2005 @ 19:15:
...
Mijn vermoeden is dat er bij een 'call' wordt gewisseld van stack, waardoor het poppen niet lukt in de 'functies' zelf. Daarentegen stond in de intel boeken dat zolang er niet tussen security levels wordt geswitched, dat er dan niets met de stack pointer gebeurt bij een call. Waar ga ik dus de mist in?
Het gaat hier inderdaad fout. Bij een call wordt het return address op de stack gezet. Met pop haal je deze eraf. Het moet dus zoiets worden:
code:
1
2
3
4
5
6
7
8
9
    push        msg
    call        PutStr
    add         esp, 4
    ;...

PutStr:
    mov         esi, [esp+4]    ; retrieve position of string
    ;...
    ret

Omdat index via esp niet zo handig is, gebruikt men standaard hiervoor de base-pointer. Het wordt dan zoiets:
code:
1
2
3
4
5
6
7
PutStr:
    push        ebp
    mov         ebp, esp
    mov         esi, [ebp+8]    ; retrieve position of string
    ;...
    leave
    ret

.
2)
Edit: Na wat testjes ben ik erachter dat PutStr inderdaad wordt aangeroepen. PutChar echter nooit.
.oisyn schreef op donderdag 09 juni 2005 @ 19:53:
code:
1
2
 or al,al
 ret


Zou je niet returnen als de zero flag geset is, ipv altijd returnen?
(btw, het is assembly, de assembler is het programma dat je code compileert)

En denk je ook niet dat het handiger is om asm eerst in het algemeen een beetje te begrijpen, door wat DOS .com LINUX programmaatjes te maken die je makkelijk kunt controleren met een debugger, ipv meteen bootloaders te maken die totaal niet te debuggen zijn? :)
.
3)
Onder linux kan je interrupt 0x10 niet gebruiken. Strings printen gaat via interrupt 0x80. AT&T voorbeeld (hier gejat):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.data                                   # section declaration
msg:
    .string     "Hello, world!\n"       # our dear string
msgend:
    .equ        len, msgend - msg       # length of our dear string

.text                                   # section declaration
.globl main      # we must export the entry point to the ELF linker or loader.
main:

# write our string to stdout
        movl    $4,%eax         # system call number (sys_write)
        movl    $1,%ebx         # first argument: file handle (stdout)
        movl    $msg,%ecx       # second argument: pointer to message to write
        movl    $len,%edx       # third argument: message length
        int     $0x80           # call kernel

# and exit
        movl    $1,%eax         # system call number (sys_exit)
        xorl    %ebx,%ebx       # first syscall argument: exit code
        int     $0x80           # call kernel

[ Voor 4% gewijzigd door Daos op 10-06-2005 20:13 ]


  • RSpliet
  • Registratie: Juni 2003
  • Laatst online: 27-11-2025
Daos schreef op vrijdag 10 juni 2005 @ 13:19:
Waarom gebruik je geen C (of C++)? Het programmeren gaat daarin veel sneller en de code is overzichtelijker.
Ja dat weet ik wel, ik ben ook (voorlopig althans :+) niet van plan om enorme lappen code te schrijven in Assembly. Ik wil echter wel begrijpen wat er allemaal gebeurt. Het bovenstaande stukje code bijvoorbeeld dat ik postte is niet iets dat ik zo enorm hard nodig heb. Ik begrijp deze echter wel. Ik had ook inderdaad door dat er iets niet goed gaat met het pushen en poppen, dus ik heb daar al een beetje mee gespeelt. Zeg maar, k vind t gewoon leuk, en dat is toch het belangrijkste, of niet? :+

[ Voor 4% gewijzigd door RSpliet op 10-06-2005 22:48 ]

Schaadt het niet, dan baat het niet

Pagina: 1