栈帧模拟(协程前奏)
2020-02-21 本文已影响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");
}