All of the offsets are perfect. Though there are somethings that are wrong/not-optimal with the code:
• Always use the CLD instruction before string instructions such as STOSB/MOVSB and etc if you are planning to copy/store by going forward in memory.
• You could simply move the [dest] parameter to EDI instead of copying to EAX first.
•
(IMPORTANT): when the STOSB instruction is done, it has decremented ECX to zero and incremented EDI as many times as the original EDI. For example if EDI was 10 at first and ECX was 5, when STOSB is done, ECX will be 0 and EDI will be 15 (10 + original ECX = 10 + 5 = 15). Therefore when you are setting the return value of the function by moving EDI to EAX, you are getting an inaccurate pointer. If I were you, I would simply access the [dest] parameter from the stack and move it to EAX at the end of the function because the parameter in the stack is untouched.
I just coded a simple [memsetb] function for you to get some ideas (it divides the number of characters to move by 4 to see if it can use STOSD instead of STOSB to move 4 bytes at a time):
Code: Select all
; ——————————————————————————————————————————————————
PUSH DWORD 1024 ; [NumberofBytes]
PUSH DWORD 'A' ; [Value] (Pushed as a DWORD)
PUSH DWORD OFFSET String1 ; [Destination]
CALL __MemSetB ; Call the function
ADD ESP , (3*4) ; Remove 3 DWORD parameters
JMP $
; ——————————————————————————————————————————————————
__MemSetB:
; void __MemSetB (void* Destination, char Value, DWORD NumberofBytes); CDECL;
PUSH EBX ; Preserve the Base Index
PUSH ECX ; Preserve the Count Register
PUSH EDX ; Preserve the Data Register
PUSH EDI ; Preserve the Destination Index
PUSHFD ; Preserve the 32-bit Flags Register
PUSH EBP ; Preserve the Base Pointer
MOV EBP , ESP ; Creat the Stack Frame
CLD ; Copy and move forward (IMPORTANT)
XOR EAX , EAX ; Set the result to zero (Failure
MOV ECX , DWORD PTR [EBP + (9*4)] ; *ECX = [NumberofBytes]
TEST ECX , ECX ; If the number of bytes is zero ...
JZ .EP ; ... Jump to the end of the function
MOV EDI , DWORD PTR [EBP + (7*4)] ; *EDI = [Destination]
MOV EAX , DWORD PTR [EBP + (8*4)] ; *EAX = [Value]
AND EAX , 0x000000FF ; Only keep the Least Significant Byte
MOV EDX , ECX ; Get a copy of [NumberofBytes] in EDX
AND EDX , 0x00000003 ; EDX = [NumberofBytes] MOD 4 (Remainder)
SHR ECX , 0x00000002 ; ECX = [NumberofBytes] DIV 4 (Quotient)
TEST ECX , ECX ; See if we have to move any DWORDs
JZ .MoveBytes ; Jump to ... if not
.MoveDWORDs: ; Start storing 4 bytes at a time
MOV EBX , EAX ; EBX = [Value]
SHL EBX , 0x00000008 ; Byte#1 of EBX = [Value]
OR EAX , EBX ; EAX = 0x0000[Value][Value]
MOV EBX , EAX ; EBX = 0x0000[Value][Value]
SHL EBX , 0x00000010 ; EBX = 0x[Value][Value]0000
OR EAX , EBX ; EAX = [Value][Value][Value][Value]
REP STOSD ; Store 4 characters at a time in ES:EDI
.MoveBytes: ; Move as many as 0 to 3 bytes
TEST EDX , EDX ; See if we have to move any bytes (if left)
JZ .SetResult ; Set the return value if not
MOV ECX , EDX ; ECX = Number of bytes to copy
REP STOSB ; Start storing from AL to ES:EDI
.SetResult: ; Set the result of the funcion
MOV EAX , DWORD PTR [EBP + (7*4)] ; Set the result to [Destination]
.EP: ; End of the procedure
POP EBP ; Restore the Base Pointer
POPFD ; Restore the 32-bit Flags Register
POP EDI ; Restore the Destination Index
POP EDX ; Restore the Data Register
POP ECX ; Restore the Count Register
POP EBX ; Restore the Base Index
RET ; Return to the calling procedure
; ——————————————————————————————————————————————————
Hope that helps.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.