I just started taking a class in assembly language and we had our first project in class and I just can't seem to understand what is wrong with this code. I have tried everything from the book but to no avail
include C:\Irvine\Irvine32.inc
.data
;Variables are listed in following order VAR DATATYPE DIGITS[RADIX] with
comments showing binary version of listed digits
left DWORD 321 ;101000001b
right DWORD 4247 ;1000010010111b
total DWORD ? ;uninitialized
diff DWORD ? ;uninitialized
;Calculate length of Array and move to var ArrayLength
Array WORD 1,2,4,8,16,32,64 ;Array
ArrayLength = ($ - Array) / 2
.code
main PROC
;Move left and right to respective registers
MOV eax,left
MOV ebx,right
;Add left var and right var and store in new var called total and move to
ecx
MOV total,eax
ADD total,ebx
MOV ecx,total
;Subtract left var and right var and store in new var called diff and move
to edx
MOV diff,eax
SUB diff,ebx
MOV edx,diff
;Define a string called message containing HELLO WORLD!
message BYTE '"Hello world!"'
;Move Array to esi
MOV esi,ArrayLength
CALL DumpRegs
exit
main ENDP
END main
When I try to run it I get
Exception thrown at 0x002A368D in ASM_Proj1.exe: 0xC0000005: Access violation reading location 0x000001A6.
At line 36 which is MOV edx,diff
Any ideas what could be going on?
For the record I am using Visual Studio 2017
Related
My questions pertain to the actions that seem to happen between the line when context is changed especially concerning RSP and RBP.
Given this very simple program:
Reading symbols from ./function_call...done.
(gdb) disass main
Dump of assembler code for function main:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: mov esi,0x2
0x00000000004004df <+9>: mov edi,0x1
0x00000000004004e4 <+14>: call 0x4004b6 <add_and_7>
0x00000000004004e9 <+19>: mov eax,0x0
0x00000000004004ee <+24>: pop rbp
0x00000000004004ef <+25>: ret
End of assembler dump.
(gdb) disass add_and_7
Dump of assembler code for function add_and_7:
0x00000000004004b6 <+0>: push rbp
0x00000000004004b7 <+1>: mov rbp,rsp
0x00000000004004ba <+4>: mov DWORD PTR [rbp-0x14],edi
0x00000000004004bd <+7>: mov DWORD PTR [rbp-0x18],esi
0x00000000004004c0 <+10>: mov DWORD PTR [rbp-0x4],0x7
0x00000000004004c7 <+17>: mov edx,DWORD PTR [rbp-0x14]
0x00000000004004ca <+20>: mov eax,DWORD PTR [rbp-0x18]
0x00000000004004cd <+23>: add edx,eax
0x00000000004004cf <+25>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004004d2 <+28>: add eax,edx
0x00000000004004d4 <+30>: pop rbp
0x00000000004004d5 <+31>: ret
End of assembler dump.
(gdb) list
1 int add_and_7( int num1, int num2 ) {
2 int seven = 7;
3 return num1 + num2 + seven;
4 }
5
6 int main() {
7 add_and_7( 1, 2 );
8 return 0;
9 }
All functions start off with push rbp which I as I understand it is preserving the parent context onto the stack. How does the parent function know how to rebuild itself? Are the necessary steps built into call and ret?
Then the rsp is always moved to rbp. As I have read this sets the new stack base to be in the context of the current function. What I can't seem to figure out is when or how stack pointer was set to that point in the first place. My best guess is the assembly function call does this, is that whats happening?
Lastly when a method returns it seems like eax is the register that is used for the parent function to utilize the return of its child function. Is eax explicitly used for this or is this just a convention with my compiler and architecture?
How does the parent function know how to rebuild itself ? Are the necessary steps built into call and ret?
Before calling a function, current status of registers are saved, as well as the return address. call instruction jumps to particular address, where the called function begins. The return address is pushed onto stack. When called function returns, ret instruction pops previously pushed return address and goes to that location.
Then the rsp is always moved to rbp
rbp is previously pushed onto stack to be able to restore rbp's value from caller's function. Then, rsp is moved to rbp to create a new stack frame for callee function. The new base pointer has been set up. So currently, rbp and rsp points to the same addresses. If there are other push instructions, esp is automatically adjusted. When function is done, the pop ebp instruction restores previously pushed stack base pointer address.
Push and Pop modify the stack pointer - SP.
Call pushes FLAGS - status register as well as the RA - return address.
Ret pops the FLAGS pops and jumps to the return address.
As rkhb said, the need to keep certain registers as they are comes from the calling conventions.
I have a code that has 3 procedures, one to get an input from the user, one to display a multiplication result, and lastly one for an error message. I am trying to implement the PUSH and POP operations and get my code in to the stack. It will seem long but it makes sense to me, here it is...
.data
line BYTE "The answer is ",0
line2 BYTE "Enter a number",0
kline3 BYTE Wrong.",0
int SWORD ?
.code
Val PROC
call ReadInt
mov int,edx
cmp int, 10000
jl 1
jmp end
L1: cmp intVal1, -10000
jg 2
call error
jmp end
2: ret
Val ENDP
main PROC
call Val
call Val
imul val, val
exit
main ENDP
END main
All this simply does it call to get 2 inputs twice and then call to display the the multiplied result. My question is how do you implement push and pop in to here to have it all make sense?
I would assume that you need to push in the GetValue procedure to put in input in to the stack and then pop it after each call in the main procedure and maybe do the same with the display procedure?
I am just struggling to figure it out so any help would be great!
PS. This code is an asm file in visual studio 2010
Your first call to GetValue stores its result in intVal. But then your second call to GetValue also stores its result in intVal, so the first result is forever lost.
Your MultiplyAndDisplay function expects one of the operands in intVal, and the other operand in eax. So, what you need to do is push [intVal] after the first call to GetValue, and pop eax after the second call to GetValue.
Note that the square brackets in push [intVal] are in some notation that actually makes sense, but if I remember correctly the microsoft assembler does not support that notation which actually makes sense, so you might have to code push intVal instead, or push dword ptr intVal, or something nonsensical like that to get it to work.
Because your question is tagged MASM, this is a MASM answer:
Your code can be restructured in a way that uses the MASM directive PROC with parameters and the INVOKE directive for parameter passing:
MultiplyAndDisplay PROC val1: SDWORD, val2: SDWORD
mov eax, val1
imul eax, val2 ; signed multiply of val1 by val2
mov edx, OFFSET prompt
call WriteString ; Writes the prompt in edx
call WriteDec ; Writes the value in eax
ret
MultiplyAndDisplay ENDP
main PROC
call GetValue
push [intVal] ; PUSH firstParam to the stack
call GetValue
pop eax ; POP previous param/intVal to EAX
invoke MultiplyAndDisplay, eax, intVal ; MultiplyAndDisplay, firstParam(EAX), secondParam(intVal)
exit
main ENDP
I am trying to move stuff from a register to a variable in .CODE, but trying to do so makes my program start over in an infinite loop (no crash and no error message, but obviously broken). I don't understand what I'm doing wrong. Here is the beginning of my code where I am trying to move data; the program never even gets past this part when I include it:
.CODE
screenX DWORD 0
screenY DWORD 0
...
ProcName PROC
mov ebx, edx ;; Copy srcBitmap into ebx
mov eax, edi ;; Take given y-location (edi)
mov edx, (EECS205BITMAP PTR [ebx]).dwHeight
shr edx, 1 ;; Subtract dwHeight/2 to center
sub eax, edx
mov screenY, eax ;; Program jumps back to beginning with no error message
Seems like I'm missing something obvious, anyone have a clue?
Your application's code segment (which is actually it's .text section under Windows) isn't writable. If you want to modify these variables you need to put them in the data segment.
I am currently trying to append a null terminator to an(a?) user inputted string:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
buff DB 100h DUP(?)
stdInHandle DWORD 0
bytesRead DWORD ?
.code
start:
;read string from stdin
INVOKE GetStdHandle, -10
MOV stdInHandle, eax
INVOKE ReadFile, stdInHandle, BYTE PTR[buff], 100, ADDR bytesRead, 0
;append null terminator on CR,LF
MOV eax, bytesRead
MOV edx, BYTE PTR[buff]
SUB eax, 2
AND BYTE PTR [eax+edx], 0
RET
END start
It refuses to assemble at MOV edx, BYTE PTR[buff] and gives me an error:
error: Invalid combination of opcode and operands (or wrong CPU setting).
So I'm assuming I cannot MOV the value of BYTE PTR[buff] into register edx. So I can't even begin to test if this method of trying to apply a NULL terminator to a string will even work.
My question is, what is wrong with the above code (should I use a different register instead of edx?)
What is the best way to apply a NULL terminator to the string?
You can't move a byte value into a dword sized register. You either need to use a byte sized register such as dl, or zero-extend it with movzx. As you are working with bytes, I suggest you go with the first option.
When I had to create methods for strings without using anything from good ole Irvine, I got the length of the string, incremented what the length returned as (you need to include an extra +1 for the null-terminator) by 1, and then added 0h to the end of the string where the pointer was where the counter is.
MOV EAX, SIZEOF lpSourceString + 1 ; Get the string length of string, add 1 to include null-terminator
INVOKE allocMem, EAX ; Allocate memory for a target to copy to
LEA ESI, [lpSourceString] ; put source address in ESI
MOV EDI, EAX ; copy the dest address to another register we can increment
MOV ECX, SIZEOF lpSourceString ; Set up loop counter
We have the size of the string. Now we can add the null-terminate to it. To do that, we need to make sure that we have a pointer looking at the end of the string. So if we have a method that returns a string in EAX, EAX needs to point to the start of the string (so we leave the allocMem unmodified, instead incrementing a copy in EDI). Let's say that we are putting characters in a string:
nextByte: ; Jump label, get the next byte in the string until ECX is 0
MOV DL, [ESI] ; Get the next character in the string
MOV [EDI], DL ; Store the byte at the position of ESI
INC ESI ; Move to next char in source
INC EDI ; INCrement EDI by 1
loop nextByte ; Re-loop to get next byte
MOV byte ptr[EDI], 0h ; Add null-terminator to end of string
; EAX holds a pointer to the start of the dynamically-allocated
; 0-terminated copy of lpSourceString
MOV requires the byte ptr size specifier because neither the [EDI] memory operand nor the 0 immediate operand would imply a size for the operation. The assembler wouldn't know if you meant a byte, word, or dword store.
I have this in my MASM, but I use a String_length stdcall method I had written due to a class requirement.
This is so common that the MASM32 runtime supplies this functionality as part of its runtime. All you need to do is include the relevant code:
include \masm32\include\masm32rt.inc
Then use the StripLF function as so:
invoke StripLF, addr buff
To fix your current problem (if you want to do it manually) , you need to move the address of buff to edx instead.
mov edx, offset buff
I get a very strange (for me) crash while manually manipulating a UNICODE_STRING:
UNICODE_STRING ustrName;
UNICODE_STRING ustrPortName;
UNICODE_STRING linkName;
UCHAR m_COMPortName[6];
RtlInitUnicodeString(&ustrName, L"PortName");
status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &strPortName);
if(NT_SUCCESS(status)) // String created
{ status = WdfRegistryQueryString (hKey, &ustrName, strPortName); // strPortName is now "COM8"
if (NT_SUCCESS (status)) {
WdfStringGetUnicodeString(strPortName, &ustrPortName);
m_COMPortName[0] = (UCHAR)ustrPortName.Buffer[0];
m_COMPortName[1] = (UCHAR)ustrPortName.Buffer[1];
m_COMPortName[2] = (UCHAR)ustrPortName.Buffer[2];
m_COMPortName[3] = (UCHAR)ustrPortName.Buffer[3];
m_COMPortName[4] = (UCHAR)ustrPortName.Buffer[4];
m_COMPortName[5] = 0; // Force a null-termination
}
}
WdfRegistryClose(hKey);
RtlInitUnicodeString(&linkName, L"\\??\\COM123"); // Init with lets say COM123, Breakpoint here...
linkName.Buffer[7] = (USHORT)m_COMPortName[3]; // First digit in the COM-port number // ** THIS LINE CRASH **
linkName.Buffer[8] = (USHORT)m_COMPortName[4]; // Second digit in the COM-port number // (if any else NULL)
linkName.Buffer[9] = (USHORT)m_COMPortName[5]; // Third digit in the COM-port number // (if any else NULL)
Disassembly:
902de533 6840072e90 push offset mydriver! ?? ::FNODOBFM::'string' (902e0740) ** Breakpoint here (same as above...) **
902de538 8d45f8 lea eax,[ebp-8]
902de53b 50 push eax
902de53c ff1528202e90 call dword ptr [mydriver!_imp__RtlInitUnicodeString (902e2028)]
902de542 660fb60d23392e90 movzx cx,byte ptr [mydriver!m_COMPortName+0x3 (902e3923)] ** Start of the crashing line **
902de54a 8b55fc mov edx,dword ptr [ebp-4] ** Seems ok **
902de54d 66894a0e mov word ptr [edx+0Eh],cx ds:0023:902e074e=0031 ** CRASH!!! **
902de551 660fb60524392e90 movzx ax,byte ptr [mydriver!m_COMPortName+0x4 (902e3924)]
902de559 8b4dfc mov ecx,dword ptr [ebp-4]
902de55c 66894110 mov word ptr [ecx+10h],ax
902de560 660fb61525392e90 movzx dx,byte ptr [mydriver!m_COMPortName+0x5 (902e3925)]
902de568 8b45fc mov eax,dword ptr [ebp-4]
902de56b 66895012 mov word ptr [eax+12h],dx
Both linkName and m_COMPortName looks correct in the Watch. Whats up?
Another solution is to in some way concatenate the unicode string L"\\??\\" with the dynamically read unicode string L"COMx". But I don't know how to do that. I'm aware of MultiByteToWideChar but I'm not so fond of using it since it needs windows.h and when I include that file into my tiny KMDF-driver project the compiler gives me tons of errors...
All code made for Windows Vista in WinDDK 7600.16385.1 (KMDF)
From MSDN RtlUnicodeStringInit:
Sets the Buffer member of the UNICODE_STRING structure to the
address that the source parameter specifies.
linkName buffer points to a constant (L"\\??\\COM123") so it crashed when you try to modify it.