Hi James,

great, thank you very much! This was the most important missing piece!

Is there an ia64 machine available where I could test the package?

Best regards

Ole

On 02.06.19 00:57, James Clarke wrote:
> On 1 Jun 2019, at 15:37, Ole Streicher <[email protected]> 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
> 

Reply via email to