Question:
Write a procedure that performs simple encryption by rotating each plaintext byte a varying
number of positions in different directions. For example, in the following array that represents
the encryption key, a negative value indicates a rotation to the left and a positive value indicates
a rotation to the right. The integer in each position indicates the magnitude of the rotation:
key BYTE -2, 4, 1, 0, -3, 5, 2, -4, -4, 6
Code:
Include Irvine32.inc
.data
msg BYTE "Hello", 0
key BYTE -2, 4, 1, 0, -3, 5, 2, -4, -4, 6
.code
main proc
mov ecx, LENGTHOF key ;Loop Counter
mov edx, OFFSET msg ;EDX Holds msg and will Display it
mov esi, OFFSET key ;Point to first array element
mov ebx, 0 ;CMP number
top:
cmp [esi], ebx ;if esi < ebx
jl ShiftLeft ;jump to shift left
cmp [esi], ebx ;if esi > ebx
jg ShiftRight ;jump to shift right
cmp [esi], ebx
je NoShift
ShiftLeft:
mov cl, [esi]
SHL edx, cl
add esi, TYPE key
loop top
ShiftRight:
mov cl, [esi]
SHR edx, cl
add esi, TYPE key
loop top
NoShift:
add esi, TYPE key
loop top
call WriteString
invoke ExitProcess,0
main endp
end main
So I am having a few issues.
1.the cmp statements are going in reverse. So the first cmp should be cmping -2 and 0. -2 < 0, So it should be taking the jump and going to Shiftleft. However, it is doing the opposite and going to shiftright.
2. Am I incrementing to the next array index properly with the add esi, TYPE key line?
3. Am I understanding the question? I need to rotate my msg, "Hello", either left if the number in the array is negative, by that number, and to the right if the number is positive in the array.
Any help is great and thanks in advance.
In your comparison
cmp [esi], ebx
this does not compare [esi] with ebx. It compares ebx with [esi] which is why you think the branch decision is incorrect. As a point of technique, you don't need to test all three conditions, since the last one must be true.
cmp [esi], ebx
je NoShift
jl ShiftRight ;else fall thru to ShiftLeft
You are correctly moving the pointer to the next array position with
add esi, TYPE key
but you have forgotten to increment the message pointer edx.
I presume that you would encode the character by rotating the byte, not shifting it, and you mistakenly rotate the pointer instead of its target
mov cl, [esi]
rol BYTE PTR [edx], cl
There is another problem - you are using cx for the loop control, but you are overwriting cl (the l.s. 8 bits of cx) with the bit shift counter. I'll leave you to figure out how to get around that.
I didn't run you code so may analysis may be wrong.
The cmp [esi], ebx do compare [esi] with ebx of course (it is just a [esi]-ebx). The mistake here is that you are comparing DWORDs instead of byte. As a rule of thumb, always specify memory operand size: cmp BYTE PTR [esi], bl this way the assembler can tell you if you are doing wrong.
You made other mistakes as pointed out by #WeatherVan.
I'd like to add that you don't need to do any jump due to the way two complement works and the symmetry of rotations. Remember: jump is expensive arithmetic is not.
If you take the low 3 bit (since you are rotating 8 bit data and 2^3=8) of the key bytes, you can always rotate to the right. A rotation of, say, 2 on the left is a rotation of 6 on the right and 6 is the two complement of 2 in 3 bits.
I also think that you need to repeat the key on the message, i.e. if the message is longer than the key you need to reload it from the start.
Here a sample program in NASM that you can use to better understand my advices
BITS 32
GLOBAL _main
SECTION .data
msg db "Hello ",0
key db -2, 4, 1, 0, -3, 5, 2, -4, -4, 6
SECTION .text
_main:
mov esi, msg
.load_key:
mov ebx, 10 ;LENGTHOF key
mov edi, key
.loop:
mov cl, BYTE [edi] ;Key
lodsb ;Char of message
test al, al ;End of string?
jz .end
and cl, 07h ;We are working with 8 bit numbers, 3bits of operand are enough
ror al, cl ;Rotate
mov BYTE [esi-01h], al
inc edi ;Next char
dec ebx ;Key left
jnz .loop
jmp .load_key
.end:
ret
Related
I'm was working on some homework to print out an array as it's sorting some integers from an array. I have the code working fine, but decided to try using EAX instead of AL in my code and ran into errors. I can't figure out why that is. Is it possible to use EAX here at all?
; This program sorts an array of signed integers, using
; the Bubble sort algorithm. It invokes a procedure to
; print the elements of the array before, the bubble sort,
; once during each iteration of the loop, and once at the end.
INCLUDE Irvine32.inc
.data
myArray BYTE 5, 1, 4, 2, 8
;myArray DWORD 5, 1, 4, 2, 8
currentArray BYTE 'This is the value of array: ' ,0
startArray BYTE 'Starting array. ' ,0
finalArray BYTE 'Final array. ' ,0
space BYTE ' ',0 ; BYTE
.code
main PROC
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
MOV EBX,0 ; clearing registers, moving 0 into each, and initialize
MOV ECX,0 ; clearing registers, moving 0 into each, and initialize
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
MOV ECX, lengthOf myArray ; load ECX with # of elements of array
DEC ECX ; decrement count by 1
L1:
PUSH ECX ; save outer loop count
MOV ESI, OFFSET myArray ; point to first value
L2:
MOV AL,[ESI] ; get array value
CMP [ESI+1], AL ; compare a pair of values
JGE L3 ; if [esi] <= [edi], don't exch
XCHG AL, [ESI+1] ; exchange the pair
MOV [ESI], AL
CALL printArray ; call printArray function
CALL crlf
L3:
INC ESI ; increment esi to the next value
LOOP L2 ; inner loop
POP ECX ; retrieve outer loop count
LOOP L1 ; else repeat outer loop
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET finalArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
CALL printArray
L4 : ret
exit
main ENDP
printArray PROC uses ESI ECX
;myArray loop
MOV ESI, OFFSET myArray ; address of myArray
MOV ECX, LENGTHOF myArray ; loop counter (5 values within array)
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET currentArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
L5 :
MOV AL, [ESI] ; add an integer into eax from array
CALL writeInt
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET space
CALL writeString
POP EDX ; restores the original edx register value
ADD ESI, TYPE myArray ; point to next integer
LOOP L5 ; repeat until ECX = 0
CALL crlf
RET
printArray ENDP
END main
END printArray
; output:
;Starting array. This is the value of array: +1 +5 +4 +2 +8
;This is the value of array: +1 +4 +5 +2 +8
;This is the value of array: +1 +4 +2 +5 +8
;This is the value of array: +1 +2 +4 +5 +8
;Final array. This is the value of array: +1 +2 +4 +5 +8
As you can see the output sorts the array just fine from least to greatest. I was trying to see if I could move AL into EAX, but that gave me a bunch of errors. Is there a work around for this so I can use a 32 bit register and get the same output?
Using EAX is definitely possible, in fact you already are. You asked "I was trying to see if I could move AL into EAX, but that gave me a bunch of errors." Think about what that means. EAX is the extended AX register, and AL is the lower partition of AX. Take a look at this diagram:image of EAX register
. As you can see, moving AL into EAX using perhaps the MOVZX instruction would simply put the value in AL into EAX and fill zeroes in from right to left. You'd be moving AL into AL, and setting the rest of EAX to 0. You could actually move everything into EAX and run the program just the same and there'd be no difference because it's using the same part of memory.
Also, why are you pushing and popping EAX so much? The only reason to push/pop things from the runtime stack is to recover them later, but you never do that, so you can just let whatever is in EAX at the time just die.
If you still want to do an 8-bit store, you need to use an 8-bit register. (AL is an 8-bit register. IDK why you mention 16 in the title).
x86 has widening loads (movzx and movsx), but integer stores from a register operand always take a register the same width as the memory operand. i.e. the way to store the low byte of EAX is with mov [esi], al.
In printArray, you should use movzx eax, byte ptr [esi] to zero-extend into EAX. (Or movsx to sign-extend, if you want to treat your numbers as int8_t instead of uint8_t.) This avoids needing the upper 24 bits of EAX to be zeroed.
BTW, your code has a lot of unnecessary instructions. e.g.
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
totally pointless. You don't need to "init" or "declare" a register before using it for the first time, if your first usage is write-only. What you do with EDX is amusing:
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
"Caller-saved" registers only have to be saved if you actually want the old value. I prefer the terms "call-preserved" and "call-clobbered". If writeString destroys its input register, then EDX holds an unknown value after the function returns, but that's fine. You didn't need the value anyway. (Actually I think Irvine32 functions at most destroy EAX.)
In this case, the previous instruction only zeroed the register (inefficiently). That whole block could be:
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
xor edx,edx ; edx = 0
Actually you should omit the xor-zeroing too, because you don't need it to be zeroed. You're not using it as counter in a loop or anything, all the other uses are write-only.
Also note that XCHG with memory has an implicit lock prefix, so it does the read-modify-write atomically (making it much slower than separate mov instructions to load and store).
You could load a pair of bytes using movzx eax, word ptr [esi] and use a branch to decide whether to rol ax, 8 to swap them or not. But store-forwarding stalls from byte stores forwarding to word loads isn't great either.
Anyway, this is getting way off topic from the title question, and this isn't codereview.SE.
I'm currently trying to learn Assembly, and one of the tasks I am given is to take user input integers and insert those numbers into an array. Once the array has 7 integers, I will loop through the array and print out the numbers. However, I'm currently stuck on how to insert the numbers into the array. Here is the code I have right now:
.DATA
inputIntMessage BYTE "Enter an integer: ", 0
inputStringMessage BYTE "Enter a string: ", 0
intArray DWORD 0,0,0,0,0,0,0
intCounter DWORD 0
user_input DWORD ?
.CODE
main PROC
mov eax, intCounter
mov edx, 0
top:
cmp eax, 7
je final1
jl L1
L1: intInput inputIntMessage, user_input
mov ebx, user_input
mov intArray[edx], ebx ;This is where I think the problem is.
add edx, 4
inc eax
jmp top
final1:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
next:
next: just goes to the next problem; irrelevant to this inserting into an array problem. My thinking is that I should use the offset of the array, so I can access the address of each element in the array and directly change that, but I do not know how. Can someone point me in the right direction?
EDIT: When I run the program the window prompts the user to enter an integer 7 times (which is as intended), and then prints out the first number the user entered. However, the window should be printing out all of the numbers the user entered.
The primary reason why your code only prints one number is because the code that displays the array of numbers does this:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
next:
What is missing is that you do not continue the loop after displaying the first number. You need to jump back to printarrayloop to process the next number. Add this right below inc edx:
jmp printarrayloop
There are some other things you may wish to consider. In this code:
top:
cmp eax, 7
je final1
jl L1
L1: intInput inputIntMessage, user_input
[snip]
final1:
You do cmp eax, 7. If it is equal you jump out. If it is less then you just branch to label L1 anyway. You can modify that code by removing the extraneous jl L1 branch and label. So you would have this:
top:
cmp eax, 7
je final1
intInput inputIntMessage, user_input
In this code there are some extra instructions that can be removed:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
jmp printarrayloop
next:
Similar to the previous comment I made to compare EDX to 7 using cmp edx,7. You can simply say that after comparing if it is equal to 7 then you jump out of the loop to next . If it is less than 7 it will just continue and print the number out. So your code could look like this:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
je next
intOutput intArray[ecx]
add ecx, 4
inc edx
jmp printarrayloop
next:
x86 32-bit code has a scaled addressing mode (with displacement). You can find all the addressing modes described in this summary here and more detailed description here.
You can using a scaling factor (multiply a register by 1,2,4, or 8) when doing addressing. You have code that looks like this:
mov intArray[edx], ebx
add edx, 4
EDX points to the element number you wish to display, multiplying it by 4 will account for the fact that the size of a DWORD is 4 bytes. So you can remove the add edx, 4and change the code accessing the array to:
mov intArray[edx*4], ebx
intArray[edx*4] is an address that is equivalent to intArray+(edx*4)
You can make a similar change when you output. Delete this line:
add ecx, 4
And use scaled addressing with:
intOutput intArray[ecx*4]
I have a pretty basic question:
How do you populate arrays in assembly? In high level programming languages you can use a for-loop to set a value to each index, but I'm not sure of how to accomplish the same thing assembly. I know this is wrong, but this is what I have:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD ?
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
mov ecx, LENGTHOF warray
L1:
mov ax, [edi] ;i want to move a number from warray to ax
movzx esi,ax ;i want to move that number into darray...
add edi, TYPE warray ;this points to the next number?
loop L1
call ExitProcess
main ENDP
END
Each time the loop runs, ax will be overwritten with the value of the array's index, right? Instead how do I populate darray with the array elements from warray? Any help would be very much appreciated...I'm pretty confused.
There are more than one way to populate an array and your code is almost working. One way is to use counter in the indirect address so you don't have to modify destination and source array pointers each loop:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD 4 dup (?) ; 4 elements
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
xor ecx, ecx ; clear counter
L1:
mov ax, [edi + ecx * 2] ; get number from warray
movzx [esi + ecx * 4], ax ; move number to darray
inc ecx ; increment counter
cmp ecx, LENGTHOF warray
jne L1
call ExitProcess
main ENDP
END
Of course this code could be modified to fill the array backwards to possibly save couple of bytes like you probably meant to do in your original code. Here is another way that has more compact loop:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD 4 dup (?) ; 4 elements
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
mov ecx, LENGTHOF warray - 1 ; start from end of array
L1:
mov ax, [edi + ecx * 2] ; get number from warray
movzx [esi + ecx * 4], ax ; move number to darray
loop L1
; get and set element zero separately because loop terminates on ecx = 0:
mov ax, [edi]
movzx [esi], ax
call ExitProcess
main ENDP
END
You should also note that when working with arrays of the same type you can do simple copy very efficiently using repeat prefix with instructions like MOVSD:
ExitProcess PROTO
.data
array1 DWORD 1,2,3,4
array2 DWORD 4 dup (?)
.code
main PROC
mov esi, OFFSET array1 ; source pointer in esi
mov edi, OFFSET array2 ; destination in edi
mov ecx, LENGTHOF array1 ; number of dwords to copy
cld ; clear direction flag so that pointers are increasing
rep movsd ; copy ecx dwords
call ExitProcess
main ENDP
END
You're probably not "supposed to know" this, but anyway, there were (way back when) an instruction and an instruction prefix that were made to do exactly this.
Take a look here at this Microsoft page: HERE (click on it)
On that page scroll down until you find this phrase...
"...These instructions are remnants of the x86's CISC heritage and in recent processors are actually slower than the equivalent instructions written out the long way...."
What you do is...
Put the size of the array in Ecx
Point Edi at the start of the arry
Use the appropriate string instruction to populate it
The syntax (Masm/Tasm/etc.) will probably look something like this...
Mov Ecx, The_Length_Of_The_Array ;Figure this out somehow
Lea Edi, The_Target_You_Want_To_Fill ;Define this somewhere
Now, if you want to copy from one place to another, do this...
Lea Esi, The_Source_You_Want_To_Copy ;Whatever, define it
Cld ;This is the direction flag, make it inc
Rep Movsb ;Movsb means move byte for byte
Now, if you want to stuff the same value in each byte in the arrray do this...
Mov AL, The_Value_You_Want_To_Stuff ;Define this to your liking
Cld ;This is the direction flag, make it inc
Rep Stosb ;Stosb means store AL into each byte
Again, these instructions are, for reasons others will elucidate, not cool anymore and if you use them you will get cooties or something.
There are also string instructions for comparison, "Scanning", "Loading", and so on. They were once quite useful (and still are, but the "modern" gang today won't admit it) particularly with the Rep prefix added to them.
If this helps, but you need more detail, feel free to ask.
I'm stuck on how you're supposed to take the decimal integers from an 8-bit BYTE array and somehow manage to move them into a 32-bit DWORD array within a loop. I know it has to do something with OFFSET and Movezx, but it's a little confusing to understand. Are there any helpful tips for a newbie to understand it?
EDIT:
For example:
Array1 Byte 2, 4, 6, 8, 10
.code
mov esi, OFFSET Array1
mov ecx, 5
L1:
mov al, [esi]
movzx eax, al
inc esi
Loop L1
Is this the right approach? Or am I doing it entirely wrong?
It's Assembly x86. (Using Visual Studios)
Your code is almost right. You managed to get the values from the byte array and to convert them to dword. Now you only have to put them in the dword array (which is even not defined in your program).
Anyway, here it is (FASM syntax):
; data definitions
Array1 db 2, 4, 6, 8, 10
Array2 rd 5 ; reserve 5 dwords for the second array.
; the code
mov esi, Array1
mov edi, Array2
mov ecx, 5
copy_loop:
movzx eax, byte [esi] ; this instruction assumes the numbers are unsigned.
; if the byte array contains signed numbers use
; "movsx"
mov [edi], eax ; store to the dword array
inc esi
add edi, 4 ; <-- notice, the next cell is 4 bytes ahead!
loop copy_loop ; the human-friendly labels will not affect the
; speed of the program.
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