Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running properly with ldc -g or ldc -O while setgmentfault with ldc #1057

Closed
codesun opened this issue Sep 1, 2015 · 2 comments
Closed

Running properly with ldc -g or ldc -O while setgmentfault with ldc #1057

codesun opened this issue Sep 1, 2015 · 2 comments

Comments

@codesun
Copy link

codesun commented Sep 1, 2015

Development Environment: Arch Linux(kernel 4.1) 64bit with ldc 0.15.1
This is my test code:
md.S

/*
 * Internal regbuf layout
 */
#define JB_RSP  0*8
#define JB_RBX  1*8
#define JB_RBP  2*8
#define JB_R12  3*8
#define JB_R13  4*8
#define JB_R14  5*8
#define JB_R15  6*8
#define JB_PC   7*8

        .file "md.S"
        .text

        /* setreg(regbuf env) */
.globl setreg
        .type setreg, @function
        .align 16
setreg:
        /*
         * Save registers.
         */
        movq %rbx, (JB_RBX)(%rdi)
        movq %rbp, (JB_RBP)(%rdi)
        movq %r12, (JB_R12)(%rdi)
        movq %r13, (JB_R13)(%rdi)
        movq %r14, (JB_R14)(%rdi)
        movq %r15, (JB_R15)(%rdi)
        /* Save SP */
        leaq 8(%rsp), %rdx
        movq %rdx, (JB_RSP)(%rdi)
        /* Save PC we are returning to */
        movq (%rsp), %rax
        movq %rax, (JB_PC)(%rdi)
        xorq %rax, %rax
        ret
        .size _co_setjmp, .-_co_setjmp

        /* regjmp(regbuf env, int val) */
.globl regjmp
        .type regjmp, @function
        .align 16
regjmp:
        /*
         * Restore registers.
         */
        movq (JB_RBX)(%rdi), %rbx
        movq (JB_RBP)(%rdi), %rbp
        movq (JB_R12)(%rdi), %r12
        movq (JB_R13)(%rdi), %r13
        movq (JB_R14)(%rdi), %r14
        movq (JB_R15)(%rdi), %r15
        /* Set return value */
        test %esi, %esi
        mov $01, %eax
        cmove %eax, %esi
        mov %esi, %eax
        movq (JB_PC)(%rdi), %rdx
        movq (JB_RSP)(%rdi), %rsp
        /* Jump to saved PC */
        jmpq *%rdx
        .size _co_longjmp, .-_co_longjmp

coro.d:

version( X86 ) {
    alias void*[6] regbuf;
} else version( X86_64 ) {
    alias void*[8] regbuf;
}
import std.stdio;
import std.c.stdlib;

extern(C) {
    int setreg(ref regbuf);
    void regjmp(ref regbuf, int);
}

enum {
    STK_DEFAULT_SIZE = 64 * 1024
}

struct Context {
    regbuf env;
    void* stk;
}

class Fiber {
private:
    Context ctx;
    regbuf env;
public:
    this() {
        ctx.stk = calloc(1, STK_DEFAULT_SIZE);
        if(setreg(ctx.env)) {
            run();
        }
        ctx.env[0] = ctx.stk + STK_DEFAULT_SIZE;
    }
    void run() {
        writeln("hello");
        yield();
        writeln("world");
        yield();
    }
    void call() {
        if(!setreg(env)) {
            regjmp(ctx.env, 1);
        }
    }

    void yield() {
        if(!setreg(ctx.env)) {
            regjmp(env, 1);
        }
    }
}

void main() {
    Fiber fb = new Fiber();
    fb.call();
    writeln("step1 done");
    fb.call();
    writeln("step2 done");
}

The executable file compiled by dmd or ldc -g/-O can work properly, but with ldc, it will throw segmentfault.

And I have used objdump -d to get the assembly code of exe file, and I found the problem may be inside the following area:

  401380:   74 0e                   je     401390 <_D4coro5Fiber6__ctorMFZC4coro5Fiber+0x60>
  401382:   48 8b 44 24 10          mov    0x10(%rsp),%rax
  401387:   48 8b 08                mov    (%rax),%rcx

%rax = 0, how is it come?

@redstar
Copy link
Member

redstar commented Sep 1, 2015

I have not checked this but I suspect that this an instance of issue #666.

@redstar
Copy link
Member

redstar commented Sep 20, 2015

This is an application bug.

You initialize the Fiber. At the end of the constructor, ctx.env[0] points to zero-allocated memory. Then you call call(). The registers are captured in env and the state from ctx is loaded. Next is the call to run(). Because it is a virtual function, this is needed to load the pointer to the vtable. this is stored on the stack - which is zero at this time. Bang!
It works with -O1 because the this pointer is stored in rbx which you saved in ctx.
It works with -g because in this case a stack frame is constructed with rbp. You save this register, too.

@redstar redstar closed this as completed Sep 20, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants