-
January 2nd, 2013, 04:10 AM
#1
Representing and dynamically creating a managed object in assembly
Hello all,
I am back yet again. I have a 64 bit library written in c++ that handle numbers of arbitrary length. The main part of the classes are in c++/cli, but all of the math stuff is written in 64 bit assembly (passed through a native c++ base class). I have been just passing in the arrays that hold the numbers to the assembly routines, but am ready to start implementing more of the structure in assembly language for various reasons, but have run into another problem I have been unable to find a solution to.
There will be three different structures I want to represent in assembly language BI (for BigInteger) BD (for BigDecimal) and BF (for BigFraction). I am figuring the structures to look like this:
Code:
BI struct
_sign qword 0
_num qword 0
BI ends
BD struct
_sign qword 0
_decimalplace qword 0
_num qword 0
BD ends
BF struct
_sign qword 0
_numerator qword 0
_denominator qword 0
BF ends
The sign in each of them will either be 0(for positive) or 1(for Negative), the decimalplace in BD holds the position of the decimal point counting from the least significant digit in String form. The actual numbers themselves are held in the arrays in the _num, _numerator, and _denominator variables and all of the qword values are treated as unsigned integers, the arrays are variable in size to accomadate however big of a number you wish. I figure calculating the position of the arrays in BI and BD will be pretty straight forward (for when one of these objects is returned from an algorithm) but the _denominator in BF could be problematic since it follows immediately after the _numerator, but we cannot know the size of the array in advance (though the size of all the arrays are stored in the first element of each array).
Anyways, if I am going to implement this I need to be able to create these objects dynamically within the assembly code. I was thinking I could create these objects in special routines that can be called when needed and thought something like this might work:
Code:
BuildBI PROC _arraysize:qword
LOCAL _as:qword
LOCAL _signpos:qword
LOCAL _numpos:qword
push rdi
mov _as, rcx
add rcx, 16
sub rsp, 28h
call GetMem64
add rsp, 28h
cmp rax, 0
je MallocError
mov qword ptr[rax],0
mov _signpos, rax
add rax, 8
mov _numpos, rax
mov rcx, _as
mov qword ptr[rax], rcx
mov rdi, 1
ClearArray:
mov qword ptr[rax+rdi*8], 0
inc rdi
cmp rdi, qword ptr[rax]
jna ClearArray
mov rax, _signpos
pop rdi
RET
BuildBI ENDP
BuildDec PROC _arraysize:qword
LOCAL _as:qword
LOCAL _signpos:qword
LOCAL _decimalplacepos:qword
LOCAL _numpos:qword
push rdi
mov _as, rcx
add rcx, 32
sub rsp, 28h
call GetMem64
add rsp, 28h
cmp rax, 0
je MallocError
mov qword ptr[rax],0
mov _signpos, rax
add rax, 8
mov _decimalplacepos, rax
mov qword ptr[rax], 0
mov rcx, _as
add rax, 8
mov _numpos, rax
mov qword ptr[rax], rcx
mov rdi, 1
ClearArray:
mov qword ptr[rax+rdi*8], 0
inc rdi
cmp rdi, qword ptr[rax]
jna ClearArray
mov rax, _signpos
pop rdi
RET
BuildDec ENDP
BuildFract PROC _arraysize1:qword, _arraysize2:qword
LOCAL _as1:qword
LOCAL _as2:qword
LOCAL _first:qword
LOCAL _signpos:qword
LOCAL _numeratorpos:qword
LOCAL _denominatorpos:qword
push rdi
mov _first, 1
mov _as1, rcx
mov _as2, rdx
add rcx, 16
add rcx, _as2
sub rsp, 28h
call GetMem64
add rsp, 28h
cmp rax, 0
je MallocError
mov _signpos, rax
mov qword ptr[rax],0
add rax, 8
mov _numeratorpos, rax
mov rcx, _as1
mov qword ptr[rax], rcx
mov rdi, 1
ClearArray:
mov qword ptr[rax+rdi*8], 0
inc rdi
cmp rdi, qword ptr[rax]
jna ClearArray
cmp _first, 0
je GoOut
mov rdx, rax
mov rax, rdi
mul eight
add rax, rdx
mov _denominatorpos, rax
mov rcx, _as2
mov qword ptr[rax], rcx
mov rdi, 1
mov _first, 0
jmp ClearArray
GoOut:
mov rax, _signpos
pop rdi
RET
BuildFract ENDP
and these would be called from Algs like the following to create return values, temporary variables, and such:
Code:
BMultiply64 PROC _val1:BI, _val2:BI
LOCAL v1s:qword
LOCAL v2s:qword
LOCAL rs:qword
LOCAL v1:qword
LOCAL v2:qword
LOCAL r:qword
LOCAL s:qword
LOCAL list:qword
LOCAL _mynum:qword
LOCAL _tlist:qword
LOCAL _ret:BI
push rbx
push rdi
push rsi
push r8
push r11
push r12
cmp initialized, 0
jne AllreadyInitialized
call BDoInit
AllreadyInitialized:
;we add the lengths of the two values and increment it, the return value will be no bigger than one more than the total
lea r11, _val1._num
lea r12, _val2._num
mov rax, qword ptr[r11]
add rax, qword ptr[r12]
inc rax
push rax
inc rax
mul eight
mov rcx, rax
sub rsp, 28h
clc
call BuildBI
add rsp, 28h
mov _ret, rax
lea r8, _ret._num
pop rax
cmp r8, 0
je MallocError
mov qword ptr[r8], rax
mov rcx, qword ptr[r8]
ZeroLoop:
;zero out the return val
mov qword ptr[r8+rcx*8], 0
loopne ZeroLoop
mov rdi, 1
mov rsi, 1
mov rcx, 1
mov rdx, 0
MultLoop:
;the main mult loop moves the current element in val1 into rax, multiplies it by the current element in _val2
;and adds and stores the result in the return val at the (_val1->Pos-1)+(_val2->Pos-1)+1 position
;the carry is kept in rdx till the begginging of the loop then temporarily stored in rbx, then rbx is added to the same position in the return val
;after running through all the elements in _val1, the alg moves to the next element in val2
mov rbx, rdx
mov rax, qword ptr[r11+rdi*8]
mul qword ptr[r12+rsi*8]
add qword ptr[r8+rcx*8], rax
adc rdx, 0
add qword ptr[r8+rcx*8], rbx
adc rdx, 0
inc rcx
inc rdi
cmp rdi, qword ptr[r11]
jna MultLoop
mov qword ptr[r8+rcx*8], rdx
mov rdx, 0
mov rdi, 1
inc rsi
mov rcx, rsi
cmp rsi, qword ptr[r12]
jna MultLoop
jmp GoOut
MallocError:
;if there was an error requesting memory try to get the error code, store it in the return value and send it back to managed code
mov rcx, 32
sub rsp, 78h
call GetMem64
add rsp, 78h
cmp rax, 0
je ErrorOut
mov _ret, rax
lea r8, _ret._num
sub rsp, 28h
clc
call GetLastError
add rsp, 28h
mov qword ptr[r8], 0
mov qword ptr[r8+8], 0
mov qword ptr[r8+16], rax
jmp GoOut
ErrorOut:
pop r12
pop r11
pop r8
pop rsi
pop rdi
pop rbx
mov rax, 0
cld
RET
GoOut:
mov rdi, qword ptr[r8]
CheckForZerosLoop:
;our final check for leading zeros and exit
cmp qword ptr[r8+rdi*8], 0
ja OutOfHere
cmp rdi, 1
jna OutOfHere
dec rdi
mov qword ptr[r8], rdi
jmp CheckForZerosLoop
OutOfHere:
mov rax, _val1._sign
xor rax, _val2._sign
mov _ret._sign, rax
mov rax, r8
pop r12
pop r11
pop r8
pop rsi
pop rdi
pop rbx
cld
RET
BMultiply64 ENDP
The above algorithm is supposed to take 2 BI values, multiply them together, and return a BI value, but I have a few questions:
1. So the multiply routine calls into the CreateBI routine to obtain a BI object dynamically with an array allready sized to hold the result, but how am I supposed to inform the runtime of the location of the array within the object so that the lea instruction will compute the correct address? In the create routine, I call for enough memory to hold the array plus a few additional bytes, then I set the very first byte up as the location for the _sign and the very next byte for the first byte of the array (which will hold the size of the array). I can see how the runtime could look at the BI struct and easily find out the location (8 bytes after the _sign value), but the _denominator array in BF would come after the _numerator array and since the _numerator is variable in size I figure I have to supply the necessary info so that the correct memory is being accessed, but how do I do that.
2. Since I never know the size of the arrays needed ahead of time, I have been declaring the arrays in my algorithms as if they were a single qword. I use them as you would a normal array, but if you were just looking at the declarations you wouldnt recognize them as arrays, this works great so far, but I have a strong feeling something in the c runtime will complain when I try passing these objects from/to the native c++ code. How am I supposed to delare an array when I wont know the size of the array until runtime?
3. Is there a way to handle these objects when it doesnt have an actual name? for instance, after calling the create routine, the address to the _sign of the object is returned in the rax register, is there a way to use the object in the register? will something like [rax]._num work?
4. Is there anything that yall can see might cause me a headache that I havent identified yet?
5. In the current version of my algorithms, the declaration for the algs would look like this:
Multiply64 PROC _val1:PTR qword, _val2:PTR qword
Do I declare the BI structures with or without the PTR part?
Multiply64 PROC _val1:PTR BI, _val2:PTR BI or
Multiply64 PROC _val1:BI, _val2:BI
I am sure Ill be coming up with more questions as I try to implement this, but these are what I see as possible problems that I have not been able to find information on yet, I am trying to come up with a clear plan before implementing it.
Thanks in advance,
Last edited by AKRichard; January 2nd, 2013 at 04:19 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|