Greg Price ??: > 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) > I know the caller's %o will be the callee's %i after the 'save', but I don't think they are saved on the stack when the 'call' or 'save' executes. Just as what I mean, these acres are just reserved for traps, those registers are saved by the trap handler or the resume(). >> 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 know the answer. From the doc you sent to me, I got:
/The SPARC V9 ABI defines the stack pointer to have bias subtracted. This means that stack pointer for 64-bit program normally contains an misaligned value,but load and store instructions generated by the com- piler subtract the required bias to generate the correct address. /so it is just a definition of the %sp, nothing else. >> 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. > I know this. Thanks, Brian > Cheers, > Greg > > >> Thanks, >> Brian >> >>> Cheers, >>> Greg >>> >>> > _______________________________________________ > mdb-discuss mailing list > mdb-discuss at opensolaris.org >