美文网首页
栈帧模拟(协程前奏)

栈帧模拟(协程前奏)

作者: 滩主 | 来源:发表于2020-02-21 20:51 被阅读0次

    EIP Instruction Pointer Register

    • The EIP register always contains the address of the next instruction to be executed.
    • You cannot directly access or change the instruction pointer.
    • However, instructions that control program flow, such as calls, jumps, loops, and interrupts, automatically change the instruction pointer.

    指令语义

    push %eax
    # 等价于
    subl $4, %esp
    movl %eax (%esp)
    
    pop %eax
    # 等价于
    movl (%esp), %eax
    addl $4, %esp
    
    call %eax
    # 等价于
    push %eip
    jmp %eax
    
    ret
    # 等价于
    pop %eip
    
    leave
    # 等价于
    movl %ebp %esp
    popl %ebp
    

    轻松跳转

    // hay.s
    .global hay
    hay:
        nop
    
    // main.c
    #include <stdio.h>
    
    int main()
    {
        asm(
            "jmp hay"
        );
        return 0;
    }
    

    天秀跳回

    # myjmp.s
    .global setjmp
    .global longjmp
    
    setjmp:
        mov 4(%esp), %eax
        mov    %ebx, (%eax)
        mov    %esi, 4(%eax)
        mov    %edi, 8(%eax)
        mov    %ebp, 12(%eax)
        lea 4(%esp), %ecx
        mov    %ecx, 16(%eax)
        mov  (%esp), %ecx
        mov    %ecx, 20(%eax)
        xor    %eax, %eax
        ret
    
    longjmp:
        mov  4(%esp),%edx
        mov  8(%esp),%eax
        test    %eax,%eax
        jnz 1f
        inc     %eax
    1:
        mov   (%edx),%ebx
        mov  4(%edx),%esi
        mov  8(%edx),%edi
        mov 12(%edx),%ebp
        mov 16(%edx),%ecx
        mov     %ecx,%esp
        mov 20(%edx),%ecx
        jmp *%ecx
    
    // main.c
    #include <stdio.h>
    
    typedef struct jmp_buf
    {
        int ebx;
        int esi;
        int edi;
        int ebp;
        int esp;
        int next;
    } jmp_buf_t ;
    
    int setjmp(jmp_buf_t*);
    void longjmp(jmp_buf_t*,int);
    
    int main()
    {
    
        jmp_buf_t env;
        int i = setjmp(&env);
        printf("i = %d\n", i);
    
        if (i != 0) return 0;
    
        longjmp(&env, 2);
    
        return 0;
    }
    
    # kwtch.s
    .global myswtch
    .global exit_resume
    myswtch:
      movl 4(%esp), %eax
      movl 8(%esp), %edx
    
      # Save old callee-save registers
      pushl %ebp
      pushl %ebx
      pushl %esi
      pushl %edi
    
      # Switch stacks
      movl %esp, (%eax)
      movl %edx, %esp
    
      # Load new callee-save registers
      popl %edi
      popl %esi
      popl %ebx
      popl %ebp
      ret
    
    exit_resume:
      movl (%ebp),%esp
    
      popl %edi
      popl %esi
      popl %ebx
      popl %ebp
      ret
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct context {
      int  edi;
      int  esi;
      int    ebx;
      int    ebp;
      int    eip;
    };
    
    struct resume {
        int ret;
    };
    
    void myswtch(struct context **old, struct context *new);
    void exit_resume();
    
    void hello();
    
    int main()
    {
    
        struct context* ctx;
        char tmp[102400];
        struct context* dest = &tmp[sizeof(tmp)-sizeof(struct context)-sizeof(struct resume)];
        dest->ebp = &ctx;
        dest->eip = &hello;
        struct resume* destResume = &tmp[sizeof(tmp)-sizeof(struct resume)];
        destResume->ret = &exit_resume;
        printf("debug\n");
        myswtch(&ctx,dest);
        printf("debug1\n");
    
        return 0;
    }
    
    void hello()
    {
        printf("hello\n");
    }
    

    相关文章

      网友评论

          本文标题:栈帧模拟(协程前奏)

          本文链接:https://www.haomeiwen.com/subject/iqmhqhtx.html