The MASM Forum

General => The Campus => Topic started by: Lonewolff on April 26, 2018, 09:56:09 AM

Title: Making return values in procs
Post by: Lonewolff on April 26, 2018, 09:56:09 AM
Hi guys,

It's easy enough to make return values of DD's etc and 'mov' them in to your variable upon return.

But what if you want a return value of a struct?

Say you have a struct containing a dozen DD's for example, how to you handle that sort of thing on return?

Thanks in advance :)
Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 10:40:14 AM
I'm not sure if you meant this?

.const
MEDIATIMERS struct
    Timer1  dd ?
    Timer2  dd ?
    Timer3  dd ?
    Timer4  dd ?
MEDIATIMERS ends

.data?
align 4
Timers    MEDIATIMERS <?>

.code
    mov Timers.Timer1,0    ; write to struct member
    mov eax,Timers.Timer4  ; read from struct member

Title: Re: Making return values in procs
Post by: jj2007 on April 26, 2018, 10:47:46 AM
Perhaps it's not yet clear. You have two options:

- mov eax,Timers.Timer4: you return one value in eax (it could be another register - unusual but possible)

- eax returns just an error code; in this case, the proc got, as one argument, a pointer to the structure, and it filled the values into that structure. So, in a sense, you "return" a filled structure, plus an error code.
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 11:07:44 AM
I mean for example something like this (in C++)

Matrix c = MatrixMultiply(a, b);

So you feed in a and b, into a proc and it outputs the result in to 'newMat'.

How do you fill 'newMat' in ASM without using it as an input parameter.

At this stage I am doing a work around and using a 'c' input param as the result. But, how do you fill 'c' without using it as a parameter?

Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 11:17:07 AM
align 16
D3DMatrixMultiply proc pOut:DWORD,pM1:DWORD,pM2:DWORD
; Out = M1 * M2

mov     eax,pM2

movaps  xmm4,[eax]
movaps  xmm5,[eax+16]
movaps  xmm6,[eax+32]
movaps  xmm7,[eax+48]

mov     edx,pM1
mov     eax,pOut

i = 0
REPT 4
movaps  xmm0,[edx+i]
movaps  xmm1,xmm0
movaps  xmm2,xmm0
movaps  xmm3,xmm0
shufps  xmm0,xmm0,00000000b
shufps  xmm1,xmm1,01010101b
shufps  xmm2,xmm2,10101010b
shufps  xmm3,xmm3,11111111b
mulps   xmm0,xmm4
mulps   xmm1,xmm5
mulps   xmm2,xmm6
mulps   xmm3,xmm7
addps   xmm2,xmm0
addps   xmm3,xmm1
addps   xmm3,xmm2
movaps  [eax+i],xmm3
i = i + 16
ENDM   
ret
D3DMatrixMultiply endp
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 11:22:19 AM
Isn't pOut a parameter though? Your Proc has 3 parameters.

You seem to be using the same 'workaround' as I am.
Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 11:27:44 AM
a == pM1
b == pM2
c == pOut

    invoke D3DMatrixMultiply,offset c,offset a,offset b

Matrices need to be 16 byte aligned.
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 11:34:06 AM
I think you are missing the meaning of question.

I'll see if I can give a better example.


Take this example then (C++)


struct Thing
{
     float a,b,c,d,e,f,g,h;
}

Thing SomeFunc(Thing blah1, Thing blah2)
{
    // do something with thing blah1 & 2
    // doesn't really matter what

    return someNewThing;
}


Thing blahC
blahC = SomeFunc(blahA, blahB);
Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 11:49:55 AM
You have to create memory to write "blahC" to.
That's exactly what my routine does pOut is your blahC.

It reads 2 matrices, multiplies them and writes the new calculated matrix in pOut.
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 11:55:41 AM
Ok, but just say you have the space created for blahC in the .data section? No way to write the result directly to that without passing as a parameter?
Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 12:19:56 PM
Yes, I have allocated memory for the empty matrix in the data section, the routine writes the result to that empty matrix memory.
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 12:21:21 PM
Yes, but you still need to pass that as a param to the function. Can't just use it as a return value.
Title: Re: Making return values in procs
Post by: Siekmanski on April 26, 2018, 12:31:22 PM
You must think in assembly now, your result is a return value of 64 bytes.
C++ maybe solves it for you, but now you're a real programmer and have to manage those things yourself.  :badgrin:
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 12:34:28 PM
Quote from: Siekmanski on April 26, 2018, 12:31:22 PM
You must think in assembly now, your result is a return value of 64 bytes.
C++ maybe solves it for you, but now you're a real programmer and have to manage those things yourself.  :badgrin:

Yep, that's cool. Just wondering if there was a way to do this natively in ASM.  :t

I'll continue thinking 'out of the box'  :biggrin:
Title: Re: Making return values in procs
Post by: jj2007 on April 26, 2018, 12:53:55 PM
You can, of course, write in your proc to a hardcoded matrix in the .data? section. But it's considered bad programming.

Your proc should work without that dirty trick. For example, you could HeapAlloc a new matrix inside the proc, and return the pointer in eax (or zero for failure); note, though, that HeapAlloc is align 8 (there is Alloc16 (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1378) - maybe you find a CRT equivalent)
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 12:58:14 PM
Yeah, I thought of something like this, but it would slowdown the code considerably.

And I have made my functions 'data.' free. So there isn't any hidden memory usage, also using registers as much as I can to keep speed right up there.
Title: Re: Making return values in procs
Post by: aw27 on April 26, 2018, 03:17:27 PM
There is no difference between C/C++ and MASM, simply C/C++ hides the complexity from you.

"...  and larger structures and class objects .... are returned in memory. To pass "in memory", the caller allocates memory and passes a pointer to it as a hidden first parameter; the callee populates the memory and returns the pointer, popping the hidden pointer when returning."

There is really no other way to do it without a lot of malabarism.
Title: Re: Making return values in procs
Post by: Lonewolff on April 26, 2018, 03:33:02 PM
Quote from: aw27 on April 26, 2018, 03:17:27 PM
There is no difference between C/C++ and MASM, simply C/C++ hides the complexity from you.

"...  and larger structures and class objects .... are returned in memory. To pass "in memory", the caller allocates memory and passes a pointer to it as a hidden first parameter; the callee populates the memory and returns the pointer, popping the hidden pointer when returning."

There is really no other way to do it without a lot of malabarism.

Ah cool. That makes a lot of sense.
Title: Re: Making return values in procs
Post by: LordAdef on May 02, 2018, 08:59:23 AM
Not for the faint of hearts, as Hutch says

welcome to the world of macho programmers, if it's only one line of code, it's not asm (surely, this is only a joke :D)
Title: Re: Making return values in procs
Post by: RuiLoureiro on May 03, 2018, 07:41:44 AM
Quote from: Ascended on April 26, 2018, 11:55:41 AM
A)   Ok, but just say you have the space created for blahC in the .data section?
B)   No way to write the result directly to that without passing as a parameter?
Your question B) seems to me curious because you dont want to pass the output address as
a parameter. And the answer to your question is YES you can ... but you have a lot of problems ...
Quote
.data?
blahC   dd 16 dup (?)     ; for matrix 4x4 real4
.code
MultiplyMatAbyB      proc   pMatA:DWORD, pMatB:DWORD
                              push   edi
                              mov   edi, offset blahC
                              ; now we have HERE the output address in edi
                              ; or replace edi by edx and comment  push and pop

                              ; do what you want


                              pop   edi
                              ret
MultiplyMatAbyB      endp
So, for each output matrix blahD, blahE,...,blahZ you need to write one procedure to do what you want to do. Is this what you want to do ? Is it usable ? (maybe if you dont need to save each result)