CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 16

Threaded View

  1. #1
    Join Date
    Aug 2009
    Location
    Finally back in Alaska
    Posts
    141

    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
  •  





Click Here to Expand Forum to Full Width

Featured