NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: dominick on August 05, 2011, 07:15:54 AM

Title: Creating a procedure
Post by: dominick 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
Title: Re: Creating a procedure
Post by: avcaballero 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
Title: Re: Creating a procedure
Post by: Frank Kotler 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

Title: Re: Creating a procedure
Post by: dominick 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
Title: Re: Creating a procedure
Post by: Frank Kotler 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