I'm just beginning to toy with masm. I don't understand why this code isn't working.
.data
MsgBoxCaption db "Iczelion Tutorial No.2",0
MsgBoxText db "Win32 Assembly is Great!",0
savedAddr DWORD ?
.code
start:
mov eax, 10
mov savedAddr, OFFSET MsgBoxText
lab:
inc MsgBoxText
MOV MsgBoxText, 'm'
cmp eax, 0
dec eax
jnz lab
invoke MessageBox, NULL, savedAddr, addr MsgBoxCaption, MB_OK
invoke ExitProcess, NULL
end start
Edit: I expect to see the first 10 characters in MsgBoxText be 'm's. Instead, only the first letter is an 'm'. I assume that inc MsgBoxText increments a pointer.
At first glance it seems like this code should do nothing except change the 'W' of Win32 to an 'a' and then to a single 'm'.
You are incrementing the word in memory at MsgBoxText, the same word, in each loop iteration.
To clobber the string using the 'm' characters, a better strategy would be to load the address of the string into a register, start storing 'm' bytes, and then increment the value in the register, as well as decrementing the counter.
Update: Ok, to answer the question in the comment, change the loop to:
lea esi, MsgBoxText
mov bl, 'm'
lab:
mov [esi], bl
inc esi
cmp eax, 0
dec eax
jnz lab
Related
I'm playing around with x86 assembly in VS 2012 trying to convert some old code I have to assembly. The problem I'm having is accessing and changing array values (the values are characters) and I'm not sure how to go about it. I've included comments so you can see my thought process
void toUpper(char *string) {
__asm{
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EBX, string
MOV ECX, 0 // counter
FOR_EXPR: // for loop
CMP EBX, 0 //compare ebx to 0
JLE END_FOR // if ebx == 0, jump to end_for
CMP EBX, 97 // compare ebx to 97
JL ELSE // if ebx < 97, jump else
CMP EBX, 122 // compare ebx to 122
JG ELSE // if ebx > 122, jump else
// subtract 32 from current array value
// jump to next element
JMP END_IF
ELSE:
// jump to next element
END_IF:
JMP FOR_EXPR
END_FOR:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
}
}
Any help is much appreciated!
Looks to me like the basic problem is that you're loading EBX with the address of the string, but then trying to use it as if it contained a byte of data from inside the string.
I'd probably do things a bit differently. I'd probably load the address of the string into ESI and use it to read the contents of the string indirectly.
mov esi, string
next_char:
lodsb
test al, al ; check for end of string
jz done
cmp al, 'a' ; ignore unless in range
bl next_char
cmp al, 'z'
bg next_char
sub al, 'a'-'A' ; convert to upper case
mov [esi-1], al ; write back to string
jmp next_char
You can use EBX for that instead of ESI, but ESI is a lot more idiomatic. There are also some tricks you could use to optimize this a little, but until you understand the basics, they'd mostly add confusion. With a modern processor, they probably wouldn't make much difference anyway--this is likely to run as fast as your bandwidth to memory anyway.
I'm working on a function in assembly where I need to count the characters in a null terminated array. I'm using visual studio. The array was made in C++ and the memory address is passed to my assembly function. Problem is my loop isn't ending once I reach null (00). I have tried using test and cmp but it seems as though 4 bytes are being compared instead of 1 byte (size of the char).
My code:
_arraySize PROC ;name of function
start: ;ebx holds address of the array
push ebp ;Save caller's frame pointer
mov ebp, esp ;establish this frame pointer
xor eax, eax ;eax = 0, array counter
xor ecx, ecx ;ecx = 0, offset counter
arrCount: ;Start of array counter loop
;test [ebx+eax], [ebx+eax] ;array address + counter(char = 1 byte)
mov ecx, [ebx + eax] ;move element into ecx to be compared
test ecx, ecx ; will be zero when ecx = 0 (null)
jz countDone
inc eax ;Array Counter and offset counter
jmp arrCount
countDone:
pop ebp
ret
_arraySize ENDP
How can I compare just 1 byte? I just thought of shifting the bytes I don't need but that seems like a waste of an instruction.
If you want to compare a single byte, use a single byte instruction:
mov cl, [ebx + eax] ;move element to be compared
test cl, cl ; will be zero when NUL
(Note that a zero character is ASCII NUL, not an ANSI NULL value.)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
x86 convert to lower case assembly
This program is to convert a 2d char array into lower case
Quickie Edit: I'm using Visual Studio 2010
int b_search (char list[100][20], int count, char* token)
{
__asm
{
mov eax, 0 ; zero out the result
mov esi, list ; move the list pointer to ESI
mov ebx, count ; move the count into EBX
mov edi, token ; move the token to search for into EDI
MOV ecx, 0
LOWERCASE_TOKEN: ;lowercase the token
OR [edi], 20h
INC ecx
CMP [edi+ecx],0
JNZ LOWERCASE_TOKEN
MOV ecx, 0
At my OR instruction, where I'm trying to change the register that contains the address to token into all lower case, I keep getting unhandled exception...access violation, and without the brackets nothing gets lowercased. Later in my code I have
LOWERCASE_ARRAY: ;for(edi = 0, edi<ebx; edi++), loops through each name
CMP ecx, ebx
JGE COMPARE
INC ecx ;ecx++
MOV edx, 0; ;edx = 0
LOWERCASE_STRING: ;while next char != 0, loop through each byte to convert to lower case
OR [esi+edx],20h ;change to lower case
INC edx
CMP [esi+edx],0 ;if [esi+edx] not zero, loop again
JNZ LOWERCASE_STRING
JMP LOWERCASE_ARRAY ;jump back to start case change of next name
and the OR instruction there seems to work perfectly so I don't know why the first won't work. Also, I am trying to convert several strings.
After I finish one string, any ideas how I would go about going to the next string (as in list[1][x], list[2][x], etc...) I tried adding 20 as in [esi+20*ecx+edi] but that doesn't work. Can I get advice on how to proceed?
One possibility:
If parameters of procedure b_search are stored as registers (register calling convention) then you override list pointer in your first asm line, because eax point to the list array:
mov eax, 0 ; zero out the result
Because:
mov esi, list ; move the list pointer to ESI
should be converted to:
mov esi, eax
Try to exchange first and second line to:
mov esi, list ; move the list pointer to ESI
mov eax, 0 ; zero out the result
I'm writing a program in Assembly that will Bubble Sort an Array of Strings. A zero length string terminates the array. I approached this by declaring a DWORD array, where the string var., that is a byte size, shall be stored. My main problem is not the bubble sort itself, but that strings that were stored in the array wasn't outputting completely.
To hopefully make it clear, here is my code:
.586
.MODEL FLAT
INCLUDE io.h ; header file for input/output
space equ 0
cr equ 0dh
.STACK 4096
.DATA
myStrings byte "Delts",0
byte "Abs",0
byte "Biceps",0
byte 0
labelStrOut byte "Output is: ", 0
stringOut dword 11 dup (?)
stringNum dword 0
stringArray dword 20 dup (?)
.CODE
_MainProc PROC
mov edi, offset myStrings
mov esi, offset stringArray
popltLp:
cmp BYTE PTR [edi], 0
jz popltDone
mov ebx, [edi]
mov DWORD PTR [esi], ebx
add esi, 4
inc stringNum
xor ecx, ecx
not ecx
xor al, al
repne scasb
jmp popltLp
popltDone:
xor edx, edx
lea esi, stringArray
mov ebx, DWORD PTR [esi]
mov stringOut, ebx
output labelStrOut, stringOut
add esi, 4
mov ebx, DWORD PTR [esi]
mov stringOut, ebx
output labelStrOut, stringOut
add esi, 4
mov ebx, DWORD PTR [esi]
mov stringOut, ebx
output labelStrOut, stringOut
outptDone:
mov eax, 0 ; exit with return code 0
ret
_MainProc ENDP
END ; end of source code
As can be seen, no Bubble Sorting is being done yet...
The lines below 'popltDone' is just me messing around to see if the strings carried over to the array just fine. However, when printed out on the screen, only 4 characters were just showing up! The entire string line was just not being printed out, which is currently driving me crazy. Can someone please tell me what I am doing wrong?
Thanks to anybody taking the time reading this.
The problem is, you aren't using string pointers correctly. Specifically, here's the code I'm referring to:
mov ebx, [edi]
mov DWORD PTR [esi], ebx
If you were to translate this into English, it would be something like this:
Move the 4 byte value pointed to by edi into ebx.
Move the value in ebx into the memory address pointed to by esi.
This is perfectly legal and may actually be what you want in some cases, but I'm guess this isn't one of them. The reason you are only seeing the first 4 characters when you output your array of strings is because you copied the literal string into your array. A DWORD is 4 bytes so you get the first 4 characters. Here's what I would write:
mov DWORD PTR [esi], edi
Which translates into:
Move the pointer value edi into the memory address pointed to by esi.
Now you have not an array of strings, but an array of string pointers. If you were to write your code in C, decompile it, this is most likely what you would see. Rewrite your comparison and output functions to work with the pointer to a string instead of the literal characters in the string and you'll fix your problem.
Assembly info: Using Visual Studio 2010 to write inline assembly embedded into C
Hello,
I am trying to write into an array of chars in C and trying to mimic the action of this C code:
resNum[posNum3] = currNum3 + '0';
currently this is what i have:
mov ebx, posNum3;
mov resNum[ebx], edx; //edx is currNum3
add resNum[ebx], 48; // add 48 because thats the value of the char '0'
I also tried doing this:
mov ebx, posNum3;
mov eax, resNum[ebx] ;// eax points to the beggining of the string
mov eax, edx; // = currnum3
add eax, 48; // + '0'
No luck with any of this, help is more than appreciated!
The problem is the instruction
mov resNum[ebx], edx
moves 4 bytes (an entire dword) into the destination, not a single byte. You probably want
mov byte ptr resNum[ebx], dl
instead. While the assembler will allow you to leave off the 'size ptr' prefix on the address, you probably don't want to, as getting it wrong leads to hard to see bugs.
My X86 asm is rusty, but...
If you're using characters (8 bits) you need to first, before you start a loop, zero out EAX and then move the char into AH or AL, something like:
; Before you start your loop
xor EAX, EAX ; If you're sure you won't overflow an 8 bit number by adding 48, this can go outside the loop
; ... code here to setup loop
mov EBX, posNum3
mov AL, resNum[EBX]
add AL, 48
; ... rest of loop
Note that the compiler will do a better job of this than you will... Unless you're Mike Abrash or someone like him :)
Avoid using expressions like
mov resNum[ebx], edx;
because you never know what is resNum. It could be an expression like esp + 4, and there is no opcode for mov [esp + ebx + 4], edx, so use small steps instead.
Also, ebx is a register that have to be preserved across calls. See http://msdn.microsoft.com/en-us/library/k1a8ss06%28v=VS.71%29.aspx for details and learn about calling conventions.
Most of inline assemblers allows using name instead of size ptr [name], so you can just write
mov al, currNum3
add al, 0x30 //'0'
mov edx, posNum3
mov ecx, resNum
mov byte ptr [edx+ecx], al
if resNum is a global array, not an function argument or local variable, you can write shorter code:
mov al, currNum3
add al, 0x30 //'0'
mov edx, posNum3
mov byte ptr [resNum+ecx], al