Brian Xu - Sun Microsystems - Beijing China wrote:
> Greg Price ??:
>>
>>> Here is an example.
>>>
>>> #*if* *defined*(__sparcv9 
>>> <http://src.opensolaris.org/source/s?defs=__sparcv9>)
>>> 79 /*
>>> 80 * The 64-bit C ABI uses a stack frame that looks like:
>>> 81 *
>>> 82 * | |
>>> 83 * |-------------------------------|
>>> 84 * | Locals, temps, saved floats |
>>> 85 * |-------------------------------|
>>> 86 * | outgoing parameters past 6 |
>>> 87 * |-------------------------------|-\
>>> 88 * | outgoing parameters thru 6 | |
>>> 89 * |-------------------------------| > minimum stack frame
>>> 90 * | 16 xwords to save IN and | |
>>> 91 * | LOCAL register on overflow | |
>>> 92 * |-------------------------------|-/-\
>>> 93 * | | |
>>> 94 * | | > v9 abi bias
>>> 95 * | | |
>>> 96 * %sp->|-------------------------------|---/
>>> 97 */
>>>
>>> [0]> ddi_regs_map_setup::dis
>>> ddi_regs_map_setup: save %sp, -0xe0, %sp
>>> ddi_regs_map_setup+4: ldx [%fp + 0x8af], %l0 >>>>> 0x8af = 0x7ff + 
>>> 0xb0, access the Locals here.
>>> ddi_regs_map_setup+8: clr %o0
>>> ddi_regs_map_setup+0xc: mov 0x1, %l1
>>> ddi_regs_map_setup+0x10: call -0x2400cc <impl_acc_hdl_alloc>
>>> ddi_regs_map_setup+0x14: clr %o1
>>> ddi_regs_map_setup+0x18: call -0x2400dc <impl_acc_hdl_get>
>>> ddi_regs_map_setup+0x1c: stx %o0, [%l0]
>>> ddi_regs_map_setup+0x20: st %l1, [%o0]
>>> ddi_regs_map_setup+0x24: mov 0x3, %l5
>>> ddi_regs_map_setup+0x28: mov 0x2, %l4
>>> ddi_regs_map_setup+0x2c: stx %i0, [%o0 + 0x18]
>>> ddi_regs_map_setup+0x30: mov %o0, %l2
>>> ddi_regs_map_setup+0x34: add %fp, 0x7cf, %o1
>>> ...
>>>
>>> My questions:
>>>
>>> 1. when the bias 0x7ff is subtracted from %sp? implicitly by the 
>>> 'save'?
>>>
>>> 2. the bias area can also be used as Locals, temps, then when it is 
>>> used? and when the explicitly allocated area is used?
>>>
>>> Thanks,
>>> Brian
>>>
>>>
>> Hi,
>>
>> The bias is only used in 64 bit mode, and it's part of the ABI (which 
>> Max had said).
>>
>> The bias is applied to the loads and stores that reference the stack 
>> and frame pointers, but not the instructions that adjust the 
>> stack/frame pointer (i.e. you won't see the bias in save or restore 
>> instructions).
>>
>> It's a not a bias area, but it's biasing the frame pointer to give 
>> you greater reach on one side. SPARC has fixed size instructions, and 
>> the offsets for the loads & stores are fixed at 13 bits (i.e. an 8K 
>> span). The stack/frame pointer is used to access the incoming args, 
>> local variables and outgoing args. If a bias were not used, the 
>> amount of memory that could be "reached" above or below the pointer 
>> would be equal (4KB each side). While the space available for 
>> incoming and outgoing args should be the same, local variables are 
>> kept in the stack frame, and are only ever accessed by the owning 
>> function itself. When we are going to pass args to a function, we 
>> store them in the callers frame, then after the function call 
>> happens, then callee accesses them from the callers frame.
>>
>> Because we only ever need to get arguments from the callers frame, we 
>> don't need to be able to reach very far on that side of the pointer, 
>> so to give us more space for local variables (which are in our own 
>> frame), we apply the bias (2KB) to all the loads and stores that 
>> access incoming args, outgoing args and local variables. This means 
>> we're limited to 2KB of incoming args, but about 6KB of outgoing args 
>> AND local variables.
>>
>> Make sense?
> Yes. Instructive.
>
> I didn't look carefully at the example I took.
> [0]> ddi_regs_map_setup::dis
> ddi_regs_map_setup: save %sp, -0xe0, %sp
> ddi_regs_map_setup+4: ldx [%fp + 0x8af], %l0 >>>>> 0x8af = 0x7ff + 0xb0,
>
> Here, we get the 7th arg that is saved on the caller's frame.
>
> Then we can also see the caller put the 7th arg on its frame:
> mpt_attach+0x3ec: add %l2, 0x78, %i4 <<<<<< get the mpt->m_datap
> mpt_attach+0x3f0: srl %i1, 0x0, %o1
> mpt_attach+0x3f4: add %l2, 0x80, %o2
> mpt_attach+0x3f8: stx %i4, [%sp + 0x8af] <<<<<<<save it on its frame
> mpt_attach+0x3fc: add %l2, 0x228, %o5
> mpt_attach+0x400: mov %i0, %o0
> mpt_attach+0x404: clr %o3
> mpt_attach+0x408: call -0x79fdaa68 <ddi_regs_map_setup>
> ...
> > ::offsetof mpt_t m_datap
> offsetof (mpt_t, m_datap) = 0x78
>
> Here is the C code:
> {
> if (ddi_regs_map_setup(dip, mem_bar, (caddr_t *)&mpt->m_reg,
> 0, 0, &mpt->m_dev_acc_attr, /&mpt->m_datap/) != DDI_SUCCESS) {
> mpt_log(mpt, CE_WARN, "map setup failed");
> cmn_err(CE_WARN, "!ID[SUNWpd.mpt.attach.4005]");
> goto fail;
> }
> }
>
> In general:
> 1. the caller save the args past 6 on its frame
Yes
> 2. each function reserve save areas for the l0-l7, i0-i7 and o0-o5 
> (16*8 = 0xb0), when spill trap occurs or thread switch occurs, those 
> register values are saved on the stack.
No. We save the locals and input registers. Remember that on SPARC the 
output registers from one frame are the input registers to the next 
frame (i.e. they are an alias)
> 3. the callee reserve area for the Locals and temps and outgoing args 
> past 6. together with the caller's bias area(I don't know how to 
> express this area, so just name as is), can be accessed by the callee 
> for its private use.
We have a minimum stack frame which is large enough to hold the 
registers + the frame is extended to hold the local variables. The bias 
isn't an area, think of it like calibrating the steering on a car or 
remote control boat. i.e. the default position is always offset by a 
particular amount.
>
> I still have the question that who produces those 'bias area' and when?
Like I was saying, it's not an area... the stack frame is the same size, 
but the stack/frame pointer is offset by a particular amount, then when 
we go to access something with it, we need to add/subtract the offset 
back in.

The best thing to do is plug some fictional values in, then see how it 
works.

I'll send you a copy of the SPARC class I used to teach... It's a little 
dated, but all this stuff is the same.
>
> still take the example:
> [0]> ddi_regs_map_setup::dis
> ddi_regs_map_setup: save %sp, -0xe0, %sp <<<<< the %o6(%sp) of the 
> caller -0xe0 = %o6 of the callee; %i6(%fp) of the callee = %o6 of the 
> caller.
> ddi_regs_map_setup+4: ldx [%fp + 0x8af], %l0 >>>>> 0x8af = 0x7ff + 
> 0xb0, access the 7th of the arg which is saved on the caller's frame.
> ddi_regs_map_setup+8: clr %o0
> ddi_regs_map_setup+0xc: mov 0x1, %l1
> ddi_regs_map_setup+0x10: call -0x2400cc <impl_acc_hdl_alloc>
> ddi_regs_map_setup+0x14: clr %o1
> ddi_regs_map_setup+0x18: call -0x2400dc <impl_acc_hdl_get>
> ...
> [0]> impl_acc_hdl_alloc::dis
> impl_acc_hdl_alloc: save %sp, -0xb0, %sp
> impl_acc_hdl_alloc+4: clr %o1
> impl_acc_hdl_alloc+8: movrne %i0, 0x1, %o1
> impl_acc_hdl_alloc+0xc: mov %o1, %i2
> impl_acc_hdl_alloc+0x10: call +0x189d14 <kmem_zalloc>
>
> It is obvious that before or just after the 'save' instruction, the 
> %sp has been moved to the bottom of the bias. so it must be the 'call' 
> or the 'save' instruction that does it. I want to know.
The save and restore instructions are like regular add and subtract, 
i.e. they add or subtract the size of the stack frame from the 
stack/frame pointer, but they also do a register window move. For a save 
(i.e. calling a function) this means all the %o's (output regs) become 
the %i's of the called function. The return address is %i7/%o7 and the 
frame / stack pointer is %i6/%o6, hence when you do a function call, the 
frame pointer for the called function *IS* the stack pointer from the 
calling function.

Cheers,
Greg

>
> Thanks,
> Brian
>>
>> Cheers,
>> Greg
>>
>

Reply via email to