• Help needed for small assembler script for the iraf package

    From James Clarke@21:1/5 to Ole Streicher on Sun Jun 2 01:00:02 2019
    On 1 Jun 2019, at 15:37, Ole Streicher <olebole@debian.org> wrote:

    Dear Itanium specialists,

    A while ago, I got the "IRAF" package accepted into Debian [1]. Although
    the code is claimed to be portable, it needs a piece of assembler
    code for each platform that provides a (sort of) setjmp() to their
    Fortran variant.

    A "C" implementation for this looks like:

    #include <setjmp.h>

    int zsvjmp_( long *buf, long *status ) {
    *status = 0;
    ((long **)buf)[0] = status;
    return sigsetjmp ((void *)((long **)buf+1),0);
    }

    however this does not work, since the "sigsetjmp" call needs to be
    replaced by a jump to sigsetjmp instead.

    There is already some working code for x64 in the original distribution:

    -------------------------------8<-----------------------------------
    .file "zsvjmp.s"
    .globl zsvjmp_
    .type zsvjmp_, @function

    zsvjmp_:
    # %rsi ... &status %rdi ... &jumpbuf
    movq %rsi, (%rdi) # store &status in jmpbuf[0]
    movl $0, (%rsi) # zero the value of status
    addq $8, %rdi # change point to &jmpbuf[1]
    movl $0, %esi # change arg2 to zero
    jmp __sigsetjmp@PLT # let sigsetjmp do the rest

    .section .note.GNU-stack,"",@progbits -------------------------------8<-----------------------------------

    The "zdojmp" counterpart is a portable C function.

    I created a small repository [2] that contains the assembler I collected
    so far as well as two test programs.

    However, I have no idea how to write the same for the ia64 platform.
    Maybe someone could help me here? Preferably under the IRAF
    license [3], so that it can be included upstream later.

    One way that worked for x32 and for arm64 was to compule the C snipped
    above (having the sigsetjmp function name by something else) with an optimizing compiler; however I didn't find cross compiler with the ia64 target?

    There is no request from the users to have this ported to ia64, and I
    doubt that ever will. My main motivation to get it ported is to check
    the package for hidden problems on "unusual" architectures.

    Hi,
    Managed to get this to work, with one caveat (explained afterwards):


    .file "zsvjmp.s"
    .explicit
    .text
    .align 64
    .global zsvjmp_#
    .type zsvjmp_#, @function
    .proc zsvjmp_#
    zsvjmp_:
    # Normally, tail calls to a different shared object are forbidden, since a
    # function in our shared object can call us without needing to save/restore
    # its gp register, but if we tail call a function outside the shared object
    # then the PLT stub will clobber gp. However, since we're writing this in
    # assembly in its own file, the compiler shouldn't be able to prove that
    # any callers are in the same shared object as us, and therefore will be
    # forced to pessimistically spill gp, so we should be safe to break the ABI
    # and let gp be trashed by our tail call.

    st8 [r33] = r0
    st8 [r32] = r33, 16
    ;;
    mov r33 = r0
    br.cond.sptk.many __sigsetjmp#
    .endp zsvjmp_#
    .section .note.GNU-stack,"",@progbits

    The caveat is that IA-64 has 128-bit floats saved as part of setjmp/longjmp, and these must be aligned, so the entire jmp_buf must be 16-byte aligned. Moreover, since zsvjmp_ uses the first long (8 bytes) of the buffer for its status pointer, the second long now also needs to be reserved so we maintain the alignment when passing it to __sigsetjmp. Thus, I needed to make two changes to your test code on IA-64, which will need to be mirrored in the actual Fortran callers (I didn't change jmptest.f, it just works by chance):

    diff --git a/zdojmp.c b/zdojmp.c
    index 547d739..093d350 100644
    --- a/zdojmp.c
    +++ b/zdojmp.c
    @@ -11,7 +11,7 @@
    void zdojmp_ (long *jmpbuf, long *status) {
    int stat = *status ? *status : 1;
    long *status_ptr = ((long **)jmpbuf)[0];
    - void *jb = (long **)jmpbuf+1;
    + void *jb = (long **)jmpbuf+2;
    *status_ptr = stat;
    siglongjmp (jb, stat);
    }
    diff --git a/zzdebug.c b/zzdebug.c
    index 824b3e3..1f350e5 100644
    --- a/zzdebug.c
    +++ b/zzdebug.c
    @@ -6,7 +6,7 @@ void zsvjmp_(void*, volatile long *);
    void zdojmp_(void*, volatile long *);

    int main(void) {
    - long jmpbuf[180];
    + long jmpbuf[180] __attribute__((__aligned__(16)));
    volatile long status = 9;
    volatile long step = 0;
    zsvjmp_((void *)jmpbuf, &status);


    Regards,
    James

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)