Author Topic: Creating a procedure  (Read 8201 times)

Offline dominick

  • Jr. Member
  • *
  • Posts: 9
Creating a procedure
« on: August 05, 2011, 07:15:54 AM »
Hi,

 I'm trying to take working code and turn it into a procedure using push and [esp] for the parameters... but all my code is doing is printing a blank line. I'm hoping that someone can explain how to push a string onto the stack and get it back as a parameter using [esp] - and how to push a number (string length) on to the stack and get it back using [esp + 4]. Also, I guess I would use 'Add esp, 4' to pop new values off of the stack?

 Here's the non-working code:

Code: [Select]
org 0x100
[section .data]
string db "testing", 13, 10
strlen equ $ - string
message db "This is a message", 13, 10
messagelength equ $ - message

[section .text]
push word [string]   ; Problem here?
call printstring
push word [message] ; Problem here?
call printstring

mov ax, 0x4c00
int 0x21


printstring:
lea si, [esp]   ; Problem here?
xor bx, bx
strtoconsole:
lodsb
inc bx
cmp bx, strlen ; want to use [esp + 4] here.
je quit
mov dl, al
mov ah, 0x06
int 0x21
jmp strtoconsole

quit:
ret

 ... and here's the code that works:

Code: [Select]
org 0x100
[section .data]
string db "testing", 13, 10
strlen equ $ - string
message db "This is a message", 13, 10
messagelength equ $ - message

[section .text]
call printstring

mov ax, 0x4c00
int 0x21


printstring:
lea si, [string]
xor bx, bx
strtoconsole:
lodsb
inc bx
cmp bx, strlen
je quit
mov dl, al
mov ah, 0x06
int 0x21
jmp strtoconsole

quit:
leave
ret

If you have any problems understanding what I'm asking (I'm not feeling too clearheaded) I can make it clearer with some comments and rephrasing my question.

 Thanks for your time,

 Dominick

Offline avcaballero

  • Full Member
  • **
  • Posts: 133
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Creating a procedure
« Reply #1 on: August 05, 2011, 09:43:45 AM »
Code: [Select]
[org 100h]
[section .text]
  push    Text                    ; Push Text address
  call    PrintString
  dec     word [lenght]
  push    word [lenght]           ; Push length variable value
  call    PrintLength
  ret

  PrintString:
    ; Proposit : Print a string passed by parameter in the stack
    ; In       : Pointer to the string in the stack
    ; Out      : None
    ; Destoys  : None
    push    bp
    mov     bp, sp
    mov     dx, word [bp+4]
    mov     ah, 9
    int     21h
    pop     bp
  ret     2
 
  PrintLength:
    ; Proposit : Prints a byte, from 0 to 9
    ; In       : Number to be printed in the stack
    ; Out      : None
    ; Destoys  : None
    push    bp
    mov     bp, sp
    mov     dl, byte [bp+4]
    or      dl, 30h
    mov     ah, 2
    int     21h
    pop     bp
  ret     2

[section .data]
  Text      db "Hello,len$"
  lenght    dw $-Text
; > strings
; Hello,len9

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Creating a procedure
« Reply #2 on: August 05, 2011, 12:31:40 PM »
Code: [Select]
org 0x100
[section .data]
string db "testing", 13, 10
strlen equ $ - string
message db "This is a message", 13, 10
messagelength equ $ - message

[section .text]
push word [string]   ; Problem here?

Yeah. You've pushed "[contents]" - the letters 't' and 'e'. Lose the square brackets to push the address, which is what you want.

Code: [Select]
call printstring
push word [message] ; Problem here?
call printstring

Yeah, same problem. Also, the "call" intruction stores the return address on the stack(!), so the address of the string is at [esp + 2], not at [esp]. This ASSumes that esp = sp - the upper word of esp is zero. This is "probably" true.

Code: [Select]
mov ax, 0x4c00
int 0x21


printstring:
lea si, [esp]   ; Problem here?

Yeah, "lea" (load effective address) puts the address of "[esp]" - just esp (= sp, we hope) in si. We want the "[contents]" of [esp] (= sp, we hope) - the address of our string... but it's at [esp + 2]... in si.

Code: [Select]
xor bx, bx
strtoconsole:
lodsb
inc bx
cmp bx, strlen ; want to use [esp + 4] here.
je quit
mov dl, al
mov ah, 0x06
int 0x21
jmp strtoconsole

quit:
ret

If I understand what you're trying to do...

Code: [Select]
org 0x100
[section .data]
string db "testing", 13, 10
strlen equ $ - string
message db "This is a message", 13, 10
messagelength equ $ - message

[section .text]
and esp, 0FFFFh  ; make sure upper word of esp is clear!

push  strlen
push string   ; address of string
call printstring
add esp, 4 ; two parameters at two bytes each

push messagelength
push message
call printstring
add esp, 4

mov ax, 0x4c00
int 0x21


printstring:
mov si, [esp + 2]   ; address
mov cx, [esp + 4]  ; length
strtoconsole:
lodsb
mov dl, al
mov ah, 0x06
int 0x21
loop strtoconsole

quit:
ret

That's untested, but will "probably" work. What Alfonso showed you is probably better! His "ret 2" makes it a "stdcall" calling convention - callee cleans up stack. The plain "ret" and "add esp, 2 * number of parameters" makes it "cdecl" calling convention - caller cleans up stack. The Windows API uses stdcall - C uses cdecl. Since you're not using either, you have the choice of doing it either way (aren't choices nice? :) ).

Best,
Frank


Offline dominick

  • Jr. Member
  • *
  • Posts: 9
Re: Creating a procedure
« Reply #3 on: August 05, 2011, 01:13:39 PM »
Thanks Frank, avcaballero, your code has helped me to handle things cleanly.

 Frank, it works perfectly. Avcaballero - the stdcall method of putting the number of used args after ret works like a charm.

 Here's what I ended up with:

Code: [Select]
org 0x100
[section .data]
string db "testing", 13, 10
strlen equ $ - string
message db "This is a message", 13, 10
messagelength equ $ - message

[section .text]
and esp, 0FFFFh  ; make sure upper word of esp is clear!

push  strlen
push string   ; address of string
call printstring

push messagelength
push message
call printstring

mov ax, 0x4c00
int 0x21


printstring:
mov si, [esp + 2]   ; address
mov cx, [esp + 4]  ; length
strtoconsole:
lodsb
mov dl, al
mov ah, 0x06
int 0x21
loop strtoconsole
.end:
ret 2
« Last Edit: August 05, 2011, 01:18:24 PM by dominick »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Creating a procedure
« Reply #4 on: August 05, 2011, 01:18:25 PM »
Good! But I think you want "ret 4" in this case - two parameters at 2 bytes each...

Best,
Frank