String length in masm - inline-assembly

I try to ouput the string length of hello in cmd screen using the following masm code.
I create a function called strlo to compute string length.
.486
.Model flat,Stdcall
option casemap :none ; case sensitive
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
strlo PROTO :DWORD
.data
msg db "Hello",0
.data?
pr dd ?
.code
start:
invoke strlo,addr msg
strlo proc parm:DWORD
xor eax,eax
mov edi,parm
l1:
cmp byte ptr [edi] ,0
je l2
inc edi
inc eax
jmp l1
l2:
ret
strlo endp
invoke StdOut,eax
invoke ExitProcess,0
end start
When I run it, I get no output.
F:\masm32>len.exe
F:\masm32>

One problem is that you have the definition of strlo in the middle of your code. It will execute where it is defined. Instead you should move it to the end and let your main code look like this:
invoke strlo,addr msg
invoke StdOut,eax
invoke ExitProcess,0

Control begins at label "start" because you wrote "end start", then yields at "ret". "invoke StdOut,eax" and "invoke ExitProcess,0" never executed. To ouput the string length of hello in cmd screen you should alter like below:
strlo proc parm:DWORD
...
strlo endp
start:
invoke strlo,addr msg
invoke StdOut,eax
...

Related

Using a default value for a function parameter which depends of other parameter

I'd like to create an script which takes an input file and optionally an output file. When you don't pass an output file, the script uses the same filename as the input but with the extension changed. I don't know how to write a default parameter which changes the extension.
#!/usr/bin/env raku
unit sub MAIN(
Str $input where *.IO.f, #= input file
Str $output = $input.IO.extension("txt"), #= output file
Bool :$copy, #= copy file
Bool :$move, #= move file
);
Unfortunately that doesn't work:
No such method 'IO' for invocant of type 'VMNull'
in block <unit> at ./copy.raku line 5
How can I do something like that?
error message is less than awesome but program not working is expected because you have in the signature
Str $output = $input.IO.extension("txt")
but the right hand side returns an IO::Path object with that extension but $output is typed to be a String. That is an error:
>>> my Str $s := "file.csv".IO.extension("txt")
Type check failed in binding; expected Str but got IO::Path (IO::Path.new("file.t...)
in block <unit> at <unknown file> line 1
>>> sub fun(Str $inp, Str $out = $inp.IO.extension("txt")) { }
&fun
>>> fun "file.csv"
Type check failed in binding to parameter '$out'; expected Str but got IO::Path (IO::Path.new("file.t...)
in sub fun at <unknown file> line 1
in block <unit> at <unknown file> line 1
Sometimes compiler detects incompatible default values:
>>> sub yes(Str $s = 3) { }
===SORRY!=== Error while compiling:
Default value '3' will never bind to a parameter of type Str
------> sub yes(Str $s = 3⏏) { }
expecting any of:
constraint
but what you have is far from a literal, so runtime detection.
To fix it, you can either
change to Str() $output = $inp.IO.extension("txt") where Str() means "accept Any object and then cast it to Str". So $output will end up being a string like "file.txt" available in MAIN.
similar alternative: Str $output = $inp.IO.extension("txt").Str but it's repetitive in Str.
change to IO::Path() $output = $inp.IO.extension("txt"). Similarly, this casts to whatever recieved to an IO::Path object, so, e.g., you'll have "file.txt".IO available in $output. If you do this, you might want to do the same for $input as well for consistency. Since IO::Path objects are idempotent to .IO (in eqv sense), no other part of the code needs changing.

How to put a value from a variable to a register?

I want to compare the end character of my string to a period.
I counted the length of the string and saved it in a variable named strlen. So, I did cmp [string + strlen], '.', but it didn't work, Then, I tried moving strlen to a register, but it didnt work as well. The program crashes. I'm using x86 32-bit Windows 10 architecture
MOV BL, [strlen-1] ;the length of the string minus 1 so i would end up
in the last character of the string
cmp [string + BL], '.'
JE func1
MOV BL, [strlen-1]
This isn't actually doing what you think it's doing. It's not storing the value of strlen - 1 in bl. Rather, it is storing the value at the address strlen - 1 in bl.
If you know C, it is the difference between:
byte* strlen = ...;
BL = *strlen - 1;
and:
byte* strlen = ...;
BL = *(strlen - 1);
In assembly notation, you can think of the brackets ([...]) as meaning "address to dereference", where "address" is interchangeable with "memory location"—like a pointer in C.
If you want to subtract 1 from the actual value of strlen, then you need to load the value into a register first, and then subtract 1 from it.
In C:
byte* strlen = ...;
bl = *strlen;
bl -= 1;
In assembly:
movzx ebx, BYTE PTR [strlen]
sub ebx, 1 ; (or dec ebx)
The BL register will now contain the length of the string, minus 1. So, you can do:
mov al, BYTE PTR [startOfString + ebx] ; al = startOfString[bl]
to load the last character in the string (which start at address startOfString) into the variable al.
Then, follow it up with:
cmp al, '.'
to set flags. Or, as you had it originally, you could use a CISC-style instruction that combines the load with the comparison:
cmp BYTE PTR [startOfString + ebx], '.'

crt_printf and ExitProcess in MASM32 with lib

crt_printf, crt_scanf, ExitProcess
Windows 7 with masm32v11r for Environment Path
in .asm file, I'd like to call crt_printf to print (or call ExitProcess to end main procedure). However my code goes with:
.386
.model flat,stdcall
option casemap:none
includelib D:\masm32\lib\msvcrt.lib
printf proto C:dword,:vararg
scanf proto C:dword,:vararg
.DATA
print_int DB "%d",0
print_char DB "%c",0
and my call procedure goes with:
PUSH offset __temp13#_cal#main
PUSH offset print_string
CALL crt_printf
ADD ESP, 8
PUSH _realCock#main
PUSH offset print_int
CALL crt_printf
ADD ESP, 8
PUSH offset __temp14#_cal#main
When I Click the button of build All, messages come with:
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: D:\masm32\bin\object_code.asm
D:\masm32\bin\object_code.asm(105) : error A2006: undefined symbol : crt_printf
D:\masm32\bin\object_code.asm(109) : error A2006: undefined symbol : crt_printf
D:\masm32\bin\object_code.asm(179) : error A2006: undefined symbol : crt_scanf
D:\masm32\bin\object_code.asm(249) : error A2006: undefined symbol : ExitProcess
Assembly Error
I've struggled with such error for 24 hours, Thx!
crt_printf is a special construct of the MASM32 developers to distiguish it from their macro printf. If you don't include \masm32\macros\macros.asm you don't need this special feature:
.386
.model flat,stdcall
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\kernel32.lib
printf proto C :dword, :vararg ; msvcrt
ExitProcess proto STDCALL :DWORD ; kernel32
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call printf
add esp, (2 * 4)
push 0
call ExitProcess
main ENDP
END main
The crt_... aliasses are declared in the msvcrt.inc:
.386
.model flat,stdcall
include \masm32\include\msvcrt.inc
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\kernel32.lib
printf proto C :dword, :vararg ; msvcrt
ExitProcess proto STDCALL :DWORD ; kernel32
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call crt_printf
add esp, (2 * 4)
push 0
call ExitProcess
main ENDP
END main
If you want the whole bunch with all declarations and macros then include masm32rt.inc:
include \masm32\include\masm32rt.inc
.DATA
fmt db "%s",10,0
hello db "Hello world!",0
.CODE
main PROC
push OFFSET hello
push OFFSET fmt
call crt_printf
add esp, (2 * 4)
printf ("Hello again: %s\n",OFFSET hello);
push 0
call ExitProcess
main ENDP
END main

Use LEA (LEAL) to create an x86 assembly counter

I'm trying to make an assembly program that adds together an unknown number of int's, like
sum(int a,int b, ...)
My code is
.globl notnull
notnull:
leal 4(%esp),%ebx
jmp next2
next:
leal 4(%ebx),%ebx
next2:
cmp $0,(%ebx)
je end
movl (%ebx),%eax
jmp next
end:
ret
I test it with this program:
#include <stdio.h>
extern int notnull();
int main()
{
int x=notnull(3,2,1,0);
printf("3,2,1,0 = %d\n",x);
x=notnull(2,1,0);
printf("2,1,0 = %d\n",x);
x=notnull(1,0);
printf("1,0 = %d\n",x);
x=notnull(0);
printf("0 = %d\n",x);
x=notnull();
printf("_ = %d\n",x);
return 0;
}
Wich gives me this output:
3,2,1,0 = 1 (#1)
2,1,0 = 1 (#2)
1,0 = 1 (#3)
0 = 8 (#4)
_ = 8 (#5)
What I want is the program to return 0 when there are no variables (see #5), and also make it work without having to have 0 as the last digit.
The perfect output of notnull(3,2) would 2 and notnull()=0
You need to read up on C argument passing conventions.
Basically, there is no way to automatically determine how many arguments are being passed to a function.
This is why all C functions either have a fixed number of arguments, or if they use variable arguments (varargs) they have one fixed argument before the variable part, which somehow expresses how many additional arguments are being passed.
Using an empty argument list makes it possible to validly call the function in any manner, but it doesn't help with the core problem of (in the function) determining how many arguments are available.
You might be able to figure it out by inspecting the stack, but of course that requires intimate knowledge of exactly how your particular compiler choses to implement the call. This might vary for different number of arguments, too.

My WM_KEYDOWN does not work when my MultiLineEdit control is in focus

i've a window created with my registered class named CLS1
invoke CreateWindow,addr CLS1,addr title,WS_OVERLAPPED,
10,10,300,300,NULL,NULL,hInstance,NULL
mov hwnd,ax
i have a mle on my window like this:
invoke CreateWindow,addr clsed,NULL,WS_CHILD or WS_VISIBLE or ES_MULTILINE
or ES_AUTOVSCROLL or WS_BORDER or WS_TABSTOP,10,10,280,250,hwnd,123,hInstance,NULL
and my message loop:
.while TRUE
invoke GetMessage,addr msg,NULL,0,0
.break .if (ax == 0)
invoke IsDialogMessage, hwnd,addr msg
.if (!ax)
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.endif
.endw
In my WndProc I want (for test) that a WM_KEYDOWN message works and show a Message Box when I press the letter 'A'. So, I've tried this:
.if (message == WM_KEYDOWN)
.if (wParam == 41h) ;41h = A or a
invoke MessageBox,NULL,addr keypress,addr title,48
.endif
But it just don't work!
If someone have any solution... please help me.
Sorry my english... i'm not american (lol)
Are you writing for 16-bit windows? If not, checking 16-bit return values and using 16-bit handles is no good:
mov hwnd,ax
.break .if (ax == 0)
.if (!ax)
use eax and things will probably go better.