• Please review our updated Terms and Rules here

HiTec C 3.09 local variable access in #asm

JonB

Veteran Member
Joined
Jan 26, 2014
Messages
1,652
Location
South Herefordshire, UK
Hello

Does anyone know how to access a local variable from within the #asm ... #endasm blocks in HiTech C under CP/M? I am using v3.09.

Global variables can easily be accessed by prefixing them with an underscore.
Locals are a bit of a mystery, anyone know how it's done?

Cheers
JonB
 
Off the top of my head - locals would be stored on the stack.

So you would need to copy the stack pointer into your favourite index register and index into the stack.

A knowledge of what is on the stack (how it is constructed by the C compiler that is) is therefore required.

Dave
 
I have tracked a manual down on the Microbee Software Preservation Project (MSPP) website at http://www.microbee-mspp.org.au detailing the stack-frame that is set-up on entry to a function.

You will need to ask for a logon (unless you can find the document elsewhere on the internet). It is called "hitech_c_compiler_z80_8086_manual.pdf" and is filed under Documentation / User_manuals. If you need some help in finding it let me know...

Page 16 of this manual details the stack frame:

Arguments to function
Return address
Saved IY
Saved IX <--- IX points to here in the function.
Local data
<--- SP points to the end of the local data.

The text in the manual is "All references to local data or parameters are made via IX. The first argument is located at (IX+6). Each parameter occupies at least 2 bytes. If a char is passed as an argument, it is expanded to int length. Local variables are accessed at locations (IX+-1) downward. If there is a register variable (there is at most one) it will be in register IY."

Hope this is of some help.

Dave

PS: I can't find a document with this name elsewhere. I assume this is the name they gave it when it was archived.
 
Thanks Dave

I had a look at the assembler code it output and saw that the local variables are addressed via IX. How damned annoying. I think the least they could have done is provide some handy macros to let us access locals easily in inline assembly code. Grrr.

Since I am not yet comfortable mucking about with stack frames I am going to have to use globals.

Cheers
JonB
 
It sounds similar to the stuff I have in my Hisoft Pascal manual, I made some Functions which return values from Inline M/C, one of those tests if a key has been pressed and if it has return true or false to the Function. In that circumstance the key was being held in iX+2 of the Function and the Function itself (of type boolean) was IX+3.

But different Variable Types hold various sizes, so CHAR, BOOLEAN are 1 byte, Integer occupies 2 Bytes and REALs hold 4 Bytes. But the areas those variables occupy could have Positive or Negative IX positions, depending on how their defined. All the ones I've described are Variables defined in a Procedure or Function. A local variable from within a those seems to have a Negative Position.
 
JonB,

You shouldn't be too frightened by stack frames - perhaps now is time to learn something new?!

Let's take this simple 'C' function:

int GB; /* A global */

void fred( int a ) {

int B = 42;

@@@

} /* End of function fred */

You should be able to replace the @@@ with assembler code something like the following (plus whatever top and tail is required by the 'C' compiler) to access the value of B:

LD H,(IX-1) ; Pick up the high-byte of local B.
LD L,(IX-2) ; Pick up the low-byte of local B.
LD _GB,HL ; Store to a global for printout purposes.

within the main function you should be able to:

Set GB to 0 [GB=0;]
Call function fred [fred();]
print out the result [printf("GB=%d.\n",GB);]

The next thing to try is to have another local variable within the function [int C = 43;]

The question then is "does B or C get stored first in the stack frame". Try it and find out.

Once you have found out the answer to this question - you should be able to work out how to access any local variable - given that you know the layout of the stack frame. You should also be able to work out how to access parameters of the function - as they are stored in a similar way (just at positive byte offsets from IX). Again, you need to work out the order that the function parameters are stored in the stack frame.

The use of LD register8,(IX-XX) will work for a small numbers of local variables. You will have to extend this mechanism for access to larger stack frames e.g.:

PUSH IX ; Get IX to DE
POP DE ; "

LD HL,offset16 ; 16 bit offset into stack frame (-ve for locals, +ve for function parameters).
ADD HL,DE ; Index into stack frame.

; HL now points at your local variable or parameter.

Hope this is of some help?

Dave

PS: Apologies for my poor Z80 assembler coding - it is probably 20 years since I last did any Z80 assembler work!
 
Could you bypass some of the assembly by using C to find the address of the local variable?

e.g.
int *GP; /* A global pointer */
void fred( int a ) {
int B = 42;
GP = &B; /* or a if you wish */

Now GP holds the address of the local variable B and can be accessed as _GP from assembly - although there's one indirection involved.
The idea is to avoid having to figure out how the stack frame lays out the various variables.

(Unless HiTech C has limitations that normal C compilers don't have..)
 
I did think of this one - but disregarded it as a solution as it makes the function non-reentrant/recursive.

My original use of GB was as a diagnostic to make sure (in this case) that the assembly code was addressing the correct local variable.

However, I may have been overthinking the solution...

Dave
 
Back
Top