Contributed by marco on from the hppa-makes-my-head-spin dept.
int rfork_thread(int flags, void *stack, void (*func)(void *arg), void *arg) { int rv; void *old_stack; /* setup stack */ asm volatile ("nop"); rv = rfork(flags); if (rv == 0) { /* run thread */ func(arg); threxit(0); } /* fixup stack */ asm volatile ("nop"); return (rv); }Well, that's simple enough, right? wrong! As you can see I was going to pull the cc -S (compile into assembly) trick here. Unfortunately that can't be done for several reasons (PIC, PLT, debugging etc). But, what does -S produce? I'll comment inside the -S output.
... rfork_thread: === function prologue === .PROC .CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=5 .ENTRY stw %r2,-20(%r30) stwm %r5,64(%r30) copy %r24,%r5 stw %r4,-60(%r30) copy %r23,%r4 stw %r3,-56(%r30) .stabn 68,0,14,.LM2-rfork_thread .LM2: .LBB2: === this is where the stack should be set up === nop .stabn 68,0,16,.LM3-rfork_thread .LM3: === call rfork === bl rfork,%r2 nop copy %r28,%r3 .LBB3: copy %r4,%r26 .stabn 68,0,18,.LM4-rfork_thread .LM4: === if rv == 0 === comib,= 0,%r28,.L3 copy %r5,%r22 .L2: .stabn 68,0,25,.LM5-rfork_thread .LM5: .LBE3: === this is where the stack should reset === nop .stabn 68,0,28,.LM6-rfork_thread .LM6: .LBE2: === return rv === copy %r3,%r28 ldw -84(%r30),%r2 ldw -60(%r30),%r4 ldw -56(%r30),%r3 bv %r0(%r2) ldwm -64(%r30),%r5 .stabn 68,0,20,.LM7-rfork_thread .LM7: .L3: === child process === .LBB4: .LBB5: === call thread === .CALL ARGW0=GR bl $$dyncall,%r31 copy %r31,%r2 .stabn 68,0,21,.LM8-rfork_thread .LM8: === call threxit(0) === ldi 0,%r26 bl threxit,%r2 ldo .L2-.L4(%r2),%r2 .L4: .LBE5: .LBE4: nop .EXIT .PROCENDWow that's almost useful. I started reading though the ABI doc and the CPU docs and I sort of get it but not quite. The portions I am still figuring out are:
* Macros like .EXIT and .CALL, what do they translate into? This should be simple enough. Just compile the whole thing and disassemble it. I am sure if I really tried I could also find the actual definitions but what's the fun in that?
* Branching is really weird due to so called spaces and actual 32 bit addressing. There are like 8 unconditional branching instructions. The problem here is that the CPU does not have a predetermined stack pointer so it is emulated in general purpose register 30 (or r30). So when a function is called the caller is responsible for setting up a stack frame, including things like a return address etc. So this is all ABI goo that I need to figure out. An added complexity is in what space things reside. Since all assembly instructions are 32 bit there is no way to load an effective 32 bit address in a single instruction. Therefore one has to offset into a space (like code segment, data segment, bss etc) or create a full blown 32 bit value. This goes like:
ldil LR'.LC1,%r25 ldo RR'.LC1(%r25),%r25This could be in between a branch too to make it more interesting (remember the instruction right after a branch always execute regardless of the branch is taken or not).
Alright more later.
(Comments are closed)
By Anonymous Coward (63.66.6.134) on
Comments
By Marco Peereboom (67.64.89.177) marco@peereboom.us on http://www.peereboom.us
Comments
By Anonymous Coward (63.66.6.134) on
They might just have pointers (even 64 bit ones :)
By Miod Vallat (82.195.186.220) miod@ on
By m0rf (68.104.17.51) on