OpenBSD Journal

Developer blog: marco

Contributed by marco on from the hppa-makes-my-head-spin dept.

A day and a half into staring at hppa code and I am starting to understand it a little. Don't get me wrong, compared to i386 or 68k this stuff is really hard and odd. I think that if I spend some more time on this it'll become clear (famous last words). Actually a lot of the complexity comes from the ABI. That is a long hard book to make it through but it is absolutely necessary to write anything useful. My one line semaphore blurb took me really longer than it should and the next step is still beyond me. Here is what we are up against:
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
        .PROCEND
Wow 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),%r25
This 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)


Comments
  1. By Anonymous Coward (63.66.6.134) on

    shouldn't miod@ and mickey@ know this hppa asm stuff?

    Comments
    1. By Marco Peereboom (67.64.89.177) marco@peereboom.us on http://www.peereboom.us

      Yeah sure but that doesn't teach *me* anything new.

      Comments
      1. By Anonymous Coward (63.66.6.134) on

        I didn't mean they *do* it for you.
        They might just have pointers (even 64 bit ones :)

    2. By Miod Vallat (82.195.186.220) miod@ on

      Why me? I am innocent! I didn't do anything, I swear!

  2. By m0rf (68.104.17.51) on

    i love how honest this stuff is on the level of the developers' knowledge, instead of the know-little-but-pretend-otherwise manner prevalent in some parts of the non-openbsd open source community.

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]