### Author Topic: Char Count Subprogram  (Read 13088 times)

#### sledge

• Jr. Member
• Posts: 19
##### Char Count Subprogram
« on: August 16, 2011, 01:34:20 AM »
My intention with this code is, to count how many characters a null terminated string has, and the return value is stored at AX.
The problem is with line (mov bx, [ebp+4+ax])

Here's the whole code:

Code: [Select]
`char_count:push ebpmov ebp, espmov ax, 0 ; character offsetloop_start:mov bx, [ebp+4+ax] ; bx = arg1[ax]cmp bx, 0 ; compare if arg1[ax] = null terminatejz end_loop ;  if previous compare true, jump to end of loopinc ax ; if not, go back to loop startjmp loop_startend_loop:pop ebpmov esp, ebpret`
Btw, I'm using dos version of NASM on a 64bit system.
« Last Edit: August 16, 2011, 02:01:36 AM by sledge »

#### Bryant Keller

• Forum Moderator
• Full Member
• Posts: 360
• Country:
##### Re: Char Count Subprogram
« Reply #1 on: August 16, 2011, 03:47:00 AM »
My intention with this code is, to count how many characters a null terminated string has, and the return value is stored at AX.
The problem is with line (mov bx, [ebp+4+ax])

Very good. But do you know why? The problem is, you're getting a WORD value, not a BYTE. So, for example. When you have the string "Hello", you're reading both the "H" and the "e" into bx and testing for 0. Then the next go-around, you're putting the "l" and "l" into bx and testing for 0 again. Finally, you put the "o" and the null terminator into bx and test for 0, but it doesn't find zero because the "o" is present! So, instead, lets try this using bytes instead.

Code: [Select]
`char_count:   push bp   mov bp, sp   mov ax, 0 ; character offsetloop_start:   mov bl, [bp+4+ax] ; bl = arg1[ax]   cmp bl, 0 ; compare if arg1[ax] = null terminate   jz end_loop ;  if previous compare true, jump to end of loop   inc ax ; if not, go back to loop start   jmp loop_startend_loop:   mov sp, bp   pop bp   ret`
I've made three minor changes to this code.
1. Since this code is running in DOS, I changed over to 16-bit register names. Not sure if it really matters, but it just looks cleaner. Also, this is probably required since you are addressing using [bp+4+ax] which means you're procedure expects arguments come after the IP and BP present on the stack.
2. I made "bx" into a "bl" so that we are only reading a byte value.
3. You pop the BP register before you update the SP register, I put these in the right order. really don't need to do this because SP isn't modified, but whatever.

Now, if you don't mind, I'm going to ASSume something here. You probably aren't wanting to access arg1[ax], rather you're probably going to be sending a pointer to the procedure as arg1. There is a slight difference in this.

Code: [Select]
`char_count:   push bp   mov bp, sp   mov si, [bp+4] ; get address from arg1loop_start:   mov bl, [si] ; bl = *arg1   cmp bl, 0 ; compare if *arg1 is null terminated   jz end_loop ;  if previous compare true, jump to end of loop   inc si ; arg1++   jmp loop_start ; if not, go back to loop startend_loop:   mov sp, bp   pop bp   ret`
There might be another small "problem" where the program will segfault, this will most likely be the case if you don't adhere to the CDECL calling convention which you seem to be using. But I won't ASSume that much and just hope that you remember to add sp, 2 in your callee.

Regards,
Bryant Keller

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Char Count Subprogram
« Reply #2 on: August 16, 2011, 04:44:57 AM »
"[bp + 4 + ax]" isn't going to work, either - accursed 16-bit addressing modes! You'd have to use si or di here instead of ax - or use 32-bit instructions in 16-bit code. This would require 32-bit hardware, but unless you bought your computer in an antique store, this won't be a problem.

As Bryant points out, your string probably isn't on the stack anyway - only the address/offset is. Do it the way Bryant shows you... but this won't return the length in ax! Umm...

Code: [Select]
`char_count:   push bp   mov bp, sp   mov si, [bp+4] ; get address from arg1loop_start:   mov bl, [si] ; bl = *arg1   cmp bl, 0 ; compare if *arg1 is null terminated   jz end_loop ;  if previous compare true, jump to end of loop   inc si ; arg1++   jmp loop_start ; if not, go back to loop startend_loop:mov ax, sisub ax, [bp + 4]   mov sp, bp   pop bp   ret`
That's still untested... I really must get dosbox working!

Best,
Frank

#### sledge

• Jr. Member
• Posts: 19
##### Re: Char Count Subprogram
« Reply #3 on: August 16, 2011, 09:34:07 PM »
Great, just compiled the code and NASM reported no errors, so the subprogram must have worked, problem is i cant see the result returned in AX because I dont know how to print a non-ascii number. Looks like I'll have to look for a DOS debugger so I can see whats going on the registers. Btw, thanks Bryant and Frank!

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Char Count Subprogram
« Reply #4 on: August 16, 2011, 10:12:59 PM »
"No errors" just means that what you did was "legal" - instructions exist such that Nasm can produce the code you asked for. Doesn't mean it'll do what you intend, or even avoid run-time errors! Being "off by one" is quite a common error.

For printing a number, some code I posted in another thread may help...

http://forum.nasm.us/index.php?topic=1209.0

Best,
Frank

#### Bryant Keller

• Forum Moderator
• Full Member
• Posts: 360
• Country:
##### Re: Char Count Subprogram
« Reply #5 on: August 18, 2011, 12:43:25 AM »
That's still untested... I really must get dosbox working!

Heh, ditto! I installed it on my netbook, but just my luck the power cable crapped out on me so I won't be using it until I get another cable. It would be nice to be able to test all the DOS related questions that pop up here. lol

#### avcaballero

• Full Member
• Posts: 133
• Country:
##### Re: Char Count Subprogram
« Reply #6 on: August 18, 2011, 08:36:43 AM »
Another example:

Code: [Select]
`; avch[org 100h][section .text]  mov     di, String  call    CalcLength  mov     di, EndChar-13  or      al, 30h     ; Cuidadín con poner más de 9 caracteres ;)  stosb  mov     dx, String  mov     ah, 9  int     21h  ret  CalcLength:    ; Calculates the length of a zstring    ; di: string offset    ; ax: length    push    cx    mov     cx, 0FFh    mov     al, 0    repnz   scasb    mov     ax, 0FEh    sub     ax, cx    pop     cx  ret[section .data]  String   db "Im a liar", 0           db "has   characters\$"  EndChar:`
PD: Long live to dosbox!

#### avcaballero

• Full Member
• Posts: 133
• Country:
##### Re: Char Count Subprogram
« Reply #7 on: August 18, 2011, 10:32:59 AM »
A bit better example
Code: [Select]
`; avch[org 100h][section .text]  mov     di, String  call    CalcLength  mov     di, EndChar-14  mov     bl, 10  div     bl  or      ax, 3030h   stosw  mov     dx, String  mov     ah, 9  int     21h  ret  CalcLength:    ; Calculates the length of a zstring    ; di: string offset    ; ax: length    push    cx    mov     cx, 0FFh    mov     al, 0    repnz   scasb    mov     ax, 0FEh    sub     ax, cx    pop     cx  ret[section .data]  String   db "I'm a liar", 0           db "has    characters\$"  EndChar:`
greetings