Wednesday, October 30, 2013

Assembly Town

Now we're going to go farther into the "Leave no trace rule".You know my last program? Well yeah it was good but there a few spots where we aren't cleaning up after ourselves but it doesn't affect our program. So what? I'll tell you what we aren't following the "Leave no trace rule". So In this program you are gonna see a lot of pushes and pops. Why? Because we push values onto the stack to save it and then we pop the values back into the registers to restore them. Well most of them anyway. The only ones that we don't push or pop are the return values (outputs). Which basically means that if there's a register that's supposed to change like on determineOperations ebx comes in as the current total and comes out as the new total so you don't push or pop ebx on determineOperations same thing with eax on raiseToThePower. Now I have just a little comment about the pushes and pops they follow LIFO (last in,first out) so we're going to pop in the opposite order we push which means if we say push eax,and then we say push ebx then we have to say pop ebx,and then we say pop eax.

Another thing we need is documentation,documentation is when you put a semi-colon on a blank line or off to the side of a line and type what you are doing there. But when you have documentation you have to make sure you follow it or else your going to have a lot of confusion so if I were you I'd update my code to follow my documentation. But one thing I want to tell you about. Once you change one procedure you have to make sure the other procedures follow it so that the program is going crazy and throwing random numbers at you. And another thing you'll want to do is put white space (blank lines) in between the different parts of the program that do different things and then put documentation above them. Now documentation doesn't hurt your program unless you forget to put a semi-colon at the front of line.
 For example:
raiseToThePower proc
;inputs:
;    ecx->current base
;    ebx->current exponent
;output:
;    eax->answer to the power
So you see how I have the word inputs then I put ecx->current base well the arrow points to the thing that the register is carrying in if it's an input or carrying out if it's an output (get it in-put out-put).

So now we are going to talk about a new word.......abstraction. Abstraction means that we don't care about the details only the important stuff. For example: we don't need to memorize every cog (line of code) in the factory (procedure) unless we're running that factory. So now our code has turned into a business doit prepares the ingredients ships them off to raiseToThePower industries raiseToThePower works with them then sends the output to determineOperations co. determineOperations modifies it then sends it off to doit then it starts all over again.                                                      

Now one more thing I want to talk about with you. You know the push and pop thing? Well I have a question about it. Since determine operations has multiple parts should we put the pops after every one of them? To that I say HA! Because of EVIL DR. REDUNDANCY! We can't have him around here so since there's a return at the end of each part we should change it to a jump and do the pops there and put the return at the end of that.

But do you know what the craziest thing about this whole thing is?.........DENDEDEDEN WE DON'T NEED TO CHANGE THE CHART AT ALL!

Now here's my code:

.model flat, c
.stack 100h
.data

 bases dword      2,3,6,9,4,2
 exponents dword  7,5,3,2,3,3
 operations dword 0,0,1,2,0,2
 total dword 0
.code
doit proc
push eax
push edx
push ebx
push ebp
push ecx
sub esp,4               ; allocating termindex so we can use it
mov ebp,esp
mov dword ptr [ebp],0

restart:
mov eax,4 ; calculate 4-byte offset into our data
mul dword ptr [ebp] ; Multiply term index
mov edx,eax ; Saving the 4-byte offset into edx

    ; calculate the next term value
mov ecx,bases[edx]
mov ebx,exponents[edx]
call raiseToThePower

    ; do the operation
mov ecx,eax
mov ebx,total
mov eax,operations[edx]
call determineOperations
mov total,ebx

; See if we need to repeat
inc dword ptr [ebp]              
cmp dword ptr [ebp],6
jl restart
pop ecx
pop ebp
pop ebx
pop edx
pop eax
add esp,4 ; deallocating termindex
  ret
doit endp

;inputs:
;   operation -> eax
;   current total -> ebx
;   term value -> ecx
;output:
;   new total -> ebx
determineOperations proc

; See which operation we need to perform
push eax
push ecx
cmp eax,0
je Addition
cmp eax,1
je Subtraction
cmp eax,2
je Multiplication
  ret

  Multiplication:
mov eax,ebx ; Move current total to the accumulator
mul ecx     ; Multiply the term value against the current total
mov ebx,eax ; Move the new total back to the return register (ebx)
    jmp popland

  Subtraction:
sub ebx,ecx
jmp popland

  Addition:
add ebx,ecx
jmp popland

  Popland:
    pop ecx
pop eax
ret
determineOperations endp


; inputs:
; ecx -> current base
;   ebx -> current exponent
; output:
;   eax -> answer to the power
raiseToThePower proc
push ebp
push edx
push ebx
push ecx
sub esp,4             ; Allocating 4 bytes on the stack for count
mov ebp,esp
mov dword ptr [ebp],0 ; Initializing count to zero
mov eax,1             ; Start with base^0
again:
cmp dword ptr [ebp],ebx
je weAreDone
mul ecx               ; Raise to the next power
inc dword ptr [ebp]
jmp again
weAreDone:
mov ebx,eax
add esp,4

pop ecx
pop ebx
pop edx
pop ebp
  ret
raiseToThePower endp

end




Tuesday, October 15, 2013

GET YOUR HANDS OFF MY STUFF!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

On this post we're going to talk more into privacy of the separate procedures. you know count and termindex? Well raisetothepower is the only procedure that uses count and doit and determineoperations are the only ones that use termindex. So why should they be in global scope (.data)? the answer is they shouldn't. So how are we going to make count invisible to doit and determineoperations but not to raisetothepower,and termindex invisible to raisetothepower but not to doit and determineoperations? Well 1st I need to introduce you to the 3 sections of ram: .code,data,and stack. But which one will we need? The answer is................
                                                              STACK
Yes stack is the one that can help us because we have esp,and ebp and we have tons of room in stack. The way we can access the stack is with ebp because that's what it's made for accessing into other sections of memory. So it's simple to access the stack all we need to do is say mov ebp,esp. But wait little red flag coming up if it's at the top of the stack it's important right so we should swim through it not over it (hee hee hee Nemo) and how we do that is we say sub esp,4 (each spot in ram is 4 bytes apart and 4 bytes is just enough room so this is our new top of the stack.) because we don't wanna mess with those jellyfish (heehee) or stomp on our ret value that will also be held in ram because it will be located at the top of the stack and if we don't update the stack pointer to a different location the instruction pointer (eip) will have the value of termindex and eip will take us off into neverneverland when we return, thus it's critical that we update the stack pointer because each procedure should be able to assume that the stack pointer is pointing to the top of the stack,so now that we have a spot that we can do whatever we want we can get going on using it as a spot for count.
remember we're trying to make each procedure as independent from each other as possible

Now we gotta talk about what I call the "Every man for himself"rule. It's basically stating that the procedures must be as independent from each other as possible so we need to make sure that doit, determineoperations, & raiseToThePower are getting as little help from each other as possible which means that they need to manage by themselves. So how are we going to do that?Well we need to talk about the "Leave no trace"rule. It means that if raiseToThePower wants to use the stack pointer and ebp sure it can use them BUT only as long as it sets them back to where they originally were.

Here's my code:

.model flat, c
.stack 100h
.data
 total dword 0
 bases dword      2,3,6,9,4,2
 exponents dword  7,5,3,2,3,3
 operations dword 0,0,1,2,0,2
.code
doit proc
;    ecx will get the base ebx will get the exponent and the program will run all the way through
; when we get back to doit we will start over again

  sub esp,4
  mov ebp,esp
  mov dword ptr [ebp],0
  ; inc may be in the wrong spot,or be inc the wrong thing because it should be inc termindex
restart:
  mov eax,4
  mul dword ptr [ebp]
  mov ebx,eax
  mov ecx,bases[ebx]
  mov ebx,exponents[ebx]
  call raiseToThePower
  call determineOperations
  inc dword ptr [ebp]                                                                                
  cmp dword ptr [ebp],6
  jl restart
  add esp,4
  ret
doit endp
;inputs:
;     termindex
;output:
;    total will have the current total
determineOperations proc
  mov ebx,eax
  mov eax,4
  mul dword ptr [ebp]

  cmp operations[eax],0
  je Addition
  cmp operations[eax],1
  je Subtraction
  cmp operations[eax],2
  je Multiplication

  ret
  Multiplication:
 mov eax,total
 mul ebx
 mov total,eax
 ret
  Subtraction:
 sub total,ebx
 ret
  Addition:
 add total,ebx
 ret
determineOperations endp


; inputs:
; ecx -> current base
;   ebx ->current exponent
; output:
;   eax ->answer to the power
raiseToThePower proc
  push dword ptr [ebp]
  sub esp,4
  mov ebp,esp
  mov dword ptr [ebp],0
  mov eax,1
again:
  cmp dword ptr [ebp],ebx
  je weAreDone
  mul ecx
  inc dword ptr [ebp]
  jmp again
weAreDone:
  add esp,4
  pop dword ptr [ebp]
  ret
raiseToThePower endp

end


So what's different about this program and other programs that we've done so far? Well at the top of raiseToThePower we have a push to save the value of ebp to the top of the stack and a pop at the end to restore it and lots of various changes that I would advise you to look for. WELL that has been the end of this post so good-bye now see ya!