![]() |
Function calls - Printable Version +- Forum (https://www.boriel.com/forum) +-- Forum: Compilers and Computer Languages (https://www.boriel.com/forum/forumdisplay.php?fid=12) +--- Forum: ZX Basic Compiler (https://www.boriel.com/forum/forumdisplay.php?fid=11) +--- Thread: Function calls (/showthread.php?tid=158) |
Function calls - britlion - 02-17-2010 When doing assembler based function calls, there's something that confuses me about the stack. Code: FUNCTION thing (num1 as uByte, num2 as uByte) as uByte When the virtual computer crashes, you can look at the registers and the stack and find out what it's doing. The stack seems to have uinteger <something> uinteger <return address> uinteger <44,num1> uinteger <44,num2> A is set to num1 First question: What's the <something> ? I end up popping it off the stack and dumping it. This worries me. Second question: If I can trust A to be num1 already, why do I have to go through num1 to get to num2? Third question: Why the 44's strapped to each byte parameter? So right now I end up: Code: POP BC ; throw this away Question 1 worries me most. What IS that extra value on the stack? Is there a better way of handling parameters - with IX+offset, say? Does the compiler set it to clean up the stack afterwards, and I shouldn't POP it at all? Sorry to whine, but this isn't documented, and I'm trying to reverse engineer it! I've got the hang of fastcall, but soemtimes I want more than one parameter. Re: Function calls - britlion - 02-24-2010 Boriel, did you notice this one? Even with the latest stack fixed version, I'm not understanding well how to do standard function calls with parameters. Where do I find my parameters? On the stack, sure... When I do Code: function thing (a as uByte, b as uByte) It seems to consist of: nn nn ; something nn nn ; return address a 44h b 44h What is that other 16 bit value on the stack? How should I be handling parameters? StdCall isn't documented in the wiki (and I documented fastcall, through reverse engineering!) It also means that if I pop my 8 bit value off the stack with POP BC - the 8 bit parameter ends up in B! ? I'm worried because following the template in the asm library: Code: Function test(a as uByte, b as uByte) as uInteger For this routine at least, left me in the rom, at the halt fall point, with interrupts disabled! A crash. In order to get it to work, and put one parameter in A, and the other in DE, it looks like I have to do Code: POP BC ; something Re: Function calls - boriel - 02-25-2010 britlion Wrote:Boriel, did you notice this one?This is an *advanced* info request :!: ![]() Glad to see you are willing to know it. britlion Wrote:When I doThe above stack frame trace is not ok. 8bit parameters (Byte, UByte) are pushed into the stack as 16bits, since Z80 stack push/pops 16bits. The Z80 stack is rather slow, and saving 1 bit on every push/pop would have had even more overhead. Since A register is mostly used with 8 bit values, and Z80 has the instructions PUSH AF and POP AF, they're used. PUSH AF and POP AF push 16 bits, storing the accumulator (A register) into the high byte of the value pushed into the stack. This means 8bit parameters takes 16bits, and only the high byte is used. So the above stack trace should look like: Code: ; aa => byte of A parameter, bb = > byte of B parameter britlion Wrote:What is that other 16 bit value on the stack? How should I be handling parameters? StdCall isn't documented in the wiki (and I documented fastcall, through reverse engineering!)I'm rather busy at this moment ![]() Believe it or not I was thinking of writing an ebook! ![]() For now, the stdCall scheme I use is the CALLEE scheme. In this calling convention, the called function will take charge of popping the function parameters out of the stack upon return. It's faster than C CALLER-scheme, and take less memory. The disadvantage of this scheme, on the other hand, is it does not allow a dynamic number of parameters, but this inconvenient can be circumvented. The stdCall convention is as follows:
Code: exx -> Saves current HL, and uses HL' Registers are used on RETURN from functions (not subs), to send return values.
So upon returning a value with size greater than 8 bits the HL register is used, and its value must be preserved during the exit sequence. britlion Wrote:It also means that if I pop my 8 bit value off the stack with POP BC - the 8 bit parameter ends up in B! ?Yes. In fact, for 8 bit operations, I use A register and H, so pop HL. britlion Wrote:I'm worried because following the template in the asm library:You can rewrite the above code, I think as: Code: pop bc Re: Function calls - britlion - 02-27-2010 Thankyou for taking the time to explain this. It will be incredibly useful! I've been spending a lot of time dabbling with adding hand-coded asm functions and routines (because ZX Basic makes it so easy to do bit of assembler with the main program!) |