Hellow,
I got a question. Could somebody explain me a little more about string processing? Because i read a lot. Bot on the forum and in books but one thing is still unclear to me and that i want to declare a byte in a proc/function so i could use it.
lets say for example
main PROC
var1 db "test",0
invoke MessageBox,0,ustr$(ebx),ADDR capt,MB_OK
ret
main ENDP
This will cause my program to crash.
I only see examples of bytes that are defined in the .data segment. But what if i don't have a fixed number of strings? That's why i want to use it in a PROC.
You are declaring a variable var1 that you don't use. Why?
ow sorry.
main PROC
var1 db "test",0
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
main ENDP
the code needs to be like this
Hi,
The way you declared var1 will result in it being executed as
the first part of your program. Put it in a data section or after
the return.
Steve
Hi steve. Thank you for your reply. But i don't want to put it in the data section because then i am stuck to a fixed number of strings that i can use. Can you explain me what you mean by after the return?
I don't understand why you're limited in strings, it is not like you are doing 16-bit coding?
Put the data AFTER the last RET instruction.
Or bracket it between a .DATA and .CODE within the PROC
main PROC
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
var1 db "test",0
main ENDP
main PROC
.DATA
var1 db "test",0
.CODE
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
main ENDP
main PROC
lea edi,@F
invoke MessageBoxA,0,ustr$(ebx),edi,MB_OK
ret
@@:
db "test",0
main ENDP
Disassembly
00000000 _main@0:
00000000 8D3D27000000 lea edi,[$$000027] ; 'test',000h
00000006 6A0A push 0Ah
00000008 6830000000 push offset ??0019
0000000D 53 push ebx
0000000E FF150000FFEF call dword ptr [__imp___ultoa]
00000014 83C40C add esp,0Ch
00000017 6A00 push 0
00000019 57 push edi
0000001A 6830000000 push offset ??0019
0000001F 6A00 push 0
00000021 E8DAFFFDEF call _MessageBoxA@16
00000026 C3 ret
00000027 $$000027: ; Xref 00000000
00000027 7465737400 db 'test',000h
Quotejmp label
test db 'my text',0
label:
invoke MessageBox,0,addr test,0,0
Under DOS code is not write protected. so
; ===============================================================
; ===============================================================
name NONAME
; ===============================================================
; === Начало программы: ===
CSEG segment
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h ; COM файл
; ===============================================================
Start:
jmp init ;на инициализацию резидента
new_16: ;новая отработка вектора 16
cmp ah, 01h ;
jne to_old_16 ;на старый вектор
pushf
call dword ptr cs:old_16 ;на старый вектор
jz @F
pushf
mov cx,0001h ;старшее слово числа микросекунд паузы
mov dx,0000h ;младшее слово числа микросекунд паузы
mov ah,86h ;функция 86h
int 15h ;пауза
popf
@@:
iret
to_old_16:
db 0eah ;Код межсегментного JMP. jmp code
old_16 dw 0, 0 ;Адрес старого обработчика.old offset address
init: ;инициализация программы
mov ax, 3516h ;прочитаем старый вектор
int 21h
mov old_16, bx ;сохраним в переменной смещение
mov old_16+2, es ;и сегмент
mov ax, 2516h ;установим новый вектор отработки прерывания 16
lea dx, new_16 ;адрес нового обработчика
int 21h
lea dx, init ;последний адрес программы, который оставляем в памяти
int 27h ;оставляем резидент в памяти и завершаемся
CSEG ends
end Start
; ===============================================================
; ===============================================================
JayJay,
How could putting your strings in the data section limit you to a "fixed number of strings", and putting them in the code section not limit you to a fixed number of strings?
(http://s1.ipicture.ru/uploads/20111215/HVWRLILI.png)
var1 must be before place where it used
var1 db "test",0
main PROC
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
main ENDP
END main
:P
Quote from: bomzvar1 must be before place where it used
touche, but only because the implementation of ADDR sucks, forward references aren't impossible to implement.
But in any case, the repeated use of "var1" or "label" doesn't work either.
I think we can infer from JayJay's request is that he wants to use the same generic string name over and over, so defining it with global scope probably isn't the way to go.
I make this examples that he understand what he do only
Hi,
I solved the problem by putting it in the .data section. I thought it was not allowed to put a .data section in a proc. I thought it was only allowed at the beginning of your .asm file :lol
Thanks for the help you all!
JayJay
QuoteI thought it was not allowed to put a .data section in a proc.
(http://smiles.kolobok.us/light_skin/yes3.gif)
Sometimes I do this (put data in code section) to make prog 512 bytes smaller. If it 1.5 kb for ex, make it 1.0 kb
i think you can forward reference if you use...
main PROC
invoke MessageBox,0,ustr$(ebx),ADDR byte ptr var1,MB_OK
ret
var1 db "test",0
main ENDP
END main
or
main PROC
invoke MessageBox,0,ustr$(ebx),offset byte ptr var1,MB_OK
ret
var1 db "test",0
main ENDP
END main
on the first pass, the assembler needs a type - not an address
at least, that's how we used to do it for .COM files using MASM v 5.10 and earlier
all the data was at the end of the code section
Bomz...
you can put data in the code section, but you cannot write to it without using VirtualProtect to alter the permissions
(http://smiles.kolobok.us/light_skin/yes3.gif)
If I may do this a make prog 1 kb smaller
Quote.386
.model flat, stdcall
option casemap :none
include \MASM32\INCLUDE\windows.inc
include \MASM32\INCLUDE\user32.inc
include \MASM32\INCLUDE\kernel32.inc
includelib \MASM32\LIB\user32.lib
includelib \MASM32\LIB\kernel32.lib
.data
mestitle db "self-modifying code",0
form db "EAX: %u", 0
.data?
buffer db 512 dup(?)
OldProtect dd ?
.code
start:
jmp DATASECTOR
var dd 0
DATASECTOR:
;Invoke GetCurrentProcessId
;invoke OpenProcess,PROCESS_VM_OPERATION,FALSE,eax
Invoke VirtualProtect, 4198400, 512, PAGE_READWRITE, addr OldProtect
;invoke GetLastError
mov var, 1
mov eax, var
invoke wsprintf,ADDR buffer,ADDR form,eax
invoke MessageBox,0,ADDR buffer,ADDR mestitle,MB_ICONASTERISK
invoke ExitProcess,0
end start
;PAGE_EXECUTE_READWRITE
;ERROR_NOACCESS
;998 (0x3E6)
Invoke VirtualProtect, 4198400, 512, PAGE_READWRITE, addr OldProtect
you got what you asked for on that one :P
Invoke VirtualProtect, offset var, 4, PAGE_EXECUTE_READWRITE, addr OldProtect
notice that - when the permission of 1 byte is changed, the entire "page" of memory changes with it
pages are, as far as i know, always 4 kb
to make write code - you need one variable - OldProtect
create it on the stack
push eax
Invoke VirtualProtect, offset var, 4, PAGE_EXECUTE_READWRITE, esp
pop edx ;EDX = old protection value
the problems with your original code:
1) you "hard-wired" the address
2) you did not allow EXECUTE in the code section :P
(http://smiles.kolobok.us/light_skin/yes3.gif)
I have no any idea for self-modyfing reason
Complete example:
include \masm32\include\masm32rt.inc
.code
AppName db "Masm is great:", 0
start: push eax
mov edi, offset AppName
Invoke VirtualProtect, edi, 4, PAGE_EXECUTE_READWRITE, esp
mov [edi], "zmob"
Invoke VirtualProtect, edi, 4, PAGE_EXECUTE, esp
pop edx ; EDX = old protection value
MsgBox 0, str$(eax), edi, MB_OK ; show return value
mov [edi], "msaM" ; let it crash
MsgBox 0, str$(eax), edi, MB_OK ; you won't see this one
exit
end start
ERROR in the ENDQuoteinclude \masm32\include\masm32rt.inc
.code
AppName db "Masm is great:", 0
start: push eax
mov edi, offset AppName
Invoke VirtualProtect, edi, 4, PAGE_EXECUTE_READWRITE, esp
mov dword ptr[edi], "zmob"
Invoke VirtualProtect, edi, 4, PAGE_EXECUTE, esp
pop edx ; EDX = old protection value
MsgBox 0, str$(eax), edi, MB_OK ; show return value
mov dword ptr[edi], "msaM" ; let it crash
MsgBox 0, str$(eax), edi, MB_OK ; you won't see this one
invoke ExitProcess,0
exit
end start
mov dword ptr[edi], "msaM" ; let it crash <--------
Jochen put that error in there for demonstration purposes
Hi,
Although i said i fixed it. I actually didn't. I thought so.... Because when i define a .data section within the proc. i can't use the name of the var in another proc.
I am trying to make a small language that converts code tot asssembly.
What i am trying to achieve is that i have a string at local level. So it only exists in the procedure.
for example
void test()
{
string str = "masm32 is fun";
}
would become but this doesn't work. :(
test PROC
str db "masm32 is fun",0
ret
test ENDP
You again seem to miss the point that the processor can't execute ASCII characters, you have to jump over them. With C it allocates space on the stack and copies the data there, it does not embedded it in-line as ASCII characters.
To use the same name repetitively you'll need to do it like this.
main1 PROC
jmp @F
var1:
db "test",0
@@:
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
main1 ENDP
main2 PROC
jmp @F
var1:
db "test",0
@@:
invoke MessageBox,0,ustr$(ebx),ADDR var1,MB_OK
ret
main2 ENDP
As clive said, you can't execute ascii strings, but the processor will try since all it does is consume bytes regardless of what you intended them for. So for example:
DB "Hello",0
is encoded as
048h, 065h, 06Ch, 06Ch, 06Fh, 00h
When the processor sees that byte sequence it will execute it as follows:
0040435c 48 dec eax
0040435d 656c ins byte ptr es:[edi],dx
0040435f 6c ins byte ptr es:[edi],dx
00404360 6f outs dx,dword ptr [esi]
00404361 0000 add byte ptr [eax],al
Obviously not what you wanted. So you have to jump past it or store it in an area that is not executed, normally it would be stored in either the DATA?, DATA or CONST section, however if its never going to be modified you can store it in the CODE section as you tried above. You can put it anywhere as long as it is not addressed before being declared (MASM limitation, GoAsm does not care), however to make sure that the processor does not try to execute it you must jump over it using a JMP instruction.
Edgar
Quote from: donkey on December 16, 2011, 02:37:06 AMYou can put it anywhere as long as it is not addressed before being declared (MASM limitation, GoAsm does not care), however to make sure that the processor does not try to execute it you must jump over it using a JMP instruction.
Another convenient place is just before the proc:
include \masm32\include\masm32rt.inc
.code
start: call MyTest
exit
mText db "The text", 0
mTitle db "The title", 0
MyTest proc
invoke MessageBox, 0, addr mText, addr mTitle, MB_OK
ret
MyTest endp
end start
By the way, JWasm allows forward references, too - a source of trouble if you use JWasm by default and want to remain compatible with Masm :wink
But the issue to be addressed is how to keep the names local to the procedure, which MASM 6.xx only does for "foo:" references not "foo db ?" ones.
JayJay is asking for locally scoped strings, without using the stack/LOCAL, with the possibility of using the same name in multiple procedures for different data.
Quote from: clive on December 16, 2011, 02:37:08 PM
But the issue to be addressed is how to keep the names local to the procedure, which MASM 6.xx only does for "foo:" references not "foo db ?" ones.
JayJay is asking for locally scoped strings, without using the stack/LOCAL, with the possibility of using the same name in multiple procedures for different data.
Hi,
Well, if the name is local, and you want it global, you have a
problem of sorts, correct? A possible way out is indirect addressing
with a pre-defined pointer to a string? Like maybe;
.DATA
StringPointer DD ?
NullString DB "Null!",0
.CODE
PROC SomeWhere
MOV StringPointer,OFFSET Foo
; Code that calls another procedure that wants the local string.
CALL Bar
; ...
; Then reset the pointer after usage.
MOV StringPointer,OFFSET NullString
RET
Foo:
DB "This is a local string.",0
ENDP
Seems a bit contrived though.
Regards,
Steve N.
Quote from: clive on December 16, 2011, 02:37:08 PM
But the issue to be addressed is how to keep the names local to the procedure, which MASM 6.xx only does for "foo:" references not "foo db ?" ones.
To complicate things further: This assembles fine...
include \masm32\include\masm32rt.inc
.code
start: call MyTest
exit
MyTest proc
jmp @F
mText:
db "The text", 0
@@:
invoke MessageBox, 0, offset mText, 0, MB_OK
ret
MyTest endp
MyTest2 proc
jmp @F
mText:
db "The text", 0
@@:
; invoke MessageBox, 0, offset mText, 0, MB_OK
ret
MyTest2 endp
end start