www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 14179] New: Posix x86_64 varargs prolog clobbers RDX


          Issue ID: 14179
           Summary: Posix x86_64 varargs prolog clobbers RDX
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Keywords: wrong-code
          Severity: blocker
          Priority: P1
         Component: DMD
          Assignee: nobody puremagic.com
          Reporter: yebblies gmail.com

The compiler generates the required prolog for varargs functions, saving the
registers and filling the __va_argsave structure.  When RDX (int reg 3) is used
for a named argument it is not saved into the varargs save space, and is used
as a temp register, discarding the argument value.

================= Prolog description ====================

    /* Generate code to move any arguments passed in registers into
     * the stack variable __va_argsave,
     * so we can reference it via pointers through va_arg().
     *   struct __va_argsave_t {
     *     size_t[6] regs;
     *     real[8] fpregs;
     *     uint offset_regs;
     *     uint offset_fpregs;
     *     void* stack_args;
     *     void* reg_args;
     *   }
     * The MOVAPS instructions seg fault if data is not aligned on
     * 16 bytes, so this gives us a nice check to ensure no mistakes.
        MOV     voff+0*8[RBP],EDI
        MOV     voff+1*8[RBP],ESI
        MOV     voff+2*8[RBP],RDX
        MOV     voff+3*8[RBP],RCX
        MOV     voff+4*8[RBP],R8
        MOV     voff+5*8[RBP],R9
        MOVZX   EAX,AL                      // AL = 0..8, # of XMM registers
        SHL     EAX,2                       // 4 bytes for each MOVAPS
        LEA     RDX,offset L2[RIP]
        SUB     RDX,RAX
        LEA     RAX,voff+6*8+0x7F[RBP]
        JMP     EDX
        MOVAPS  -0x0F[RAX],XMM7             // only save XMM registers if
actually used
        MOVAPS  -0x1F[RAX],XMM6
        MOVAPS  -0x2F[RAX],XMM5
        MOVAPS  -0x3F[RAX],XMM4
        MOVAPS  -0x4F[RAX],XMM3
        MOVAPS  -0x5F[RAX],XMM2
        MOVAPS  -0x6F[RAX],XMM1
        MOVAPS  -0x7F[RAX],XMM0
        MOV     1[RAX],offset_regs          // set __va_argsave.offset_regs
        MOV     5[RAX],offset_fpregs        // set __va_argsave.offset_fpregs
        LEA     RDX, Para.size+Para.offset[RBP]
        MOV     9[RAX],RDX                  // set __va_argsave.stack_args
        SUB     RAX,6*8+0x7F                // point to start of __va_argsave
        MOV     6*8+8*16+4+4+8[RAX],RAX     // set __va_argsave.reg_args

================= Test case ====================

import core.stdc.stdarg;

struct Loc
    const(char)* filename;
    uint linnum;
    uint charnum;

extern(C++) const(char)* func(Loc loc, const(char)* string, ...)
    return string;

void main()
    const(char)* s = "hello";
    assert(func(Loc(), s) == s);

Feb 14 2015