Reputation: 179
I've done some assembly programming on Linux and am now trying to do it on Windows using MASM. I am running into a couple issues though.
(Here I am trying to implement the strlen() function. I know the function logic/instructions aren't optimal, but I'm just trying to rig something dirty up so I can get going on implementing other C library functions.)
.386
.model flat, stdcall
option casemap:none
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
.data
testString db "test string", 0 ; 0 -> terminator
.code
my_strlen proc
mov ebp, esp ; function prologue
push esp
push ebx
push ecx
xor ecx, ecx ; set count to 0
mov bl, byte ptr [ebp + 8] ; set low of b to 1st character
repeat:
cmp bl, 0 ; if null terminator, return
jz done
inc ecx ; increase count
mov bl, byte ptr [ebp + 8 + ecx] ; increase *ebx
jmp repeat ; repeat
done:
mov eax, ecx ; return count
pop ecx ; function epilogue
pop ebx
pop esp
ret
my_strlen endp
main:
push offset testString ; result = my_strlen(testString)
call my_strlen
push eax ; StdOut(result)
call StdOut
push 0 ; ExitProcess(0)
call ExitProcess
end main
When I try to compile, it doesn't appear to like my jmp labels, throwing unmatched macro nesting, etc. Whats the proper way to do this? p.s. I am trying to avoid using MASM macros where possible, preferring to code the instructions myself.
Can someone please make this program compile? Once I see how it is done correctly I will be on my merry way, I will be able to. Yes I looked for resources and still am as this question is up.
Upvotes: 4
Views: 1515
Reputation: 1782
This is a solution with macros. The length of the string is finally stored in EAX.
First macro checks a whole DWORD from the memory and is faster than a bytewise read and check. Good for larger strings.
;//-----------------------------------------------------------------------
strlenFast MACRO stringPtr:REQ
;//-----------------------------------------------------------------------
local STRLEN_LOOP
mov eax, stringPtr
mov esi, 0
STRLEN_LOOP:
mov ebx, [eax+esi]
mov ecx, ebx
inc esi
and ebx, 0FFh
jz EOS
mov ebx, ecx
inc esi
and ebx, 0FF00h
jz EOS
mov ebx, ecx
inc esi
and ebx, 0FF0000h
jz EOS
mov ebx, ecx
inc esi
and ebx, 0FF000000h
jnz short STRLEN_LOOP
EOS:
dec esi
mov eax, esi
ENDM
A short solution with bytewise check:
;//-----------------------------------------------------------------------
strlenShort MACRO stringPtr:REQ
;//-----------------------------------------------------------------------
local STRLEN_LOOP
mov eax, stringPtr
mov esi, -1
STRLEN_LOOP:
inc esi
mov ebx, [eax+esi]
and ebx, 0FFh
jnz STRLEN_LOOP
mov eax, esi
ENDM
In main proc:
.data
anyString byte "Hello World", 0
.code
main PROC
strlenShort OFFSET anyString ;// => result in EAX
strlenFast OFFSET anyString ;// => result in EAX
Upvotes: 0
Reputation: 14399
Can someone please make this program compile?
Voilà (explanation in the comments):
.386
.model flat, stdcall
option casemap:none
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
.data
testString db "test string", 0
.code
my_strlen proc
; mov ebp, esp ; function prologue
; push esp
push ebp ; this is a correct prologue
mov ebp, esp
push ebx
push ecx
push esi
mov esi, [ebp+8] ; in [EBP+8] is a pointer
xor ecx, ecx
mov bl, byte ptr [esi]
repea: ; "repeat" is a keyword
cmp bl, 0
jz done
inc ecx
mov bl, byte ptr [esi + ecx] ; increase *esi
jmp repea ; repeat
done:
mov eax, ecx
pop esi
pop ecx
pop ebx
leave ; this is a correct epilogue
ret
my_strlen endp
main proc ; this is better
push offset testString
call my_strlen
; push eax ; StdOut(result)
push offset testString ; The MASM32-function StdOut needs only an ASCIZ-string
call StdOut
push 0
call ExitProcess
main endp
end main
I suspect you want to output the result of my_strlen. This is not possible with StdOut
because StdOut
needs a pointer to a string. You have to create a function to convert EAX
to a string.
Upvotes: 3