I need to understand HOW longjmp function works; I know what it does, but I need to know how it does it.
I tried to disas the code in gdb but I can't understand some steps. The code is:
0xb7ead420 <siglongjmp+0>: push %ebp
0xb7ead421 <siglongjmp+1>: mov %esp,%ebp
0xb7ead423 <siglongjmp+3>: sub $0x18,%esp
0xb7ead426 <siglongjmp+6>: mov %ebx,-0xc(%ebp)
0xb7ead429 <siglongjmp+9>: call 0xb7e9828f <_Unwind_Find_FDE@plt+119>
0xb7ead42e <siglongjmp+14>: add $0x12bbc6,%ebx
0xb7ead434 <siglongjmp+20>: mov %esi,-0x8(%ebp)
0xb7ead437 <siglongjmp+23>: mov 0xc(%ebp),%esi
0xb7ead43a <siglongjmp+26>: mov %edi,-0x4(%ebp)
0xb7ead43d <siglongjmp+29>: mov 0x8(%ebp),%edi
0xb7ead440 <siglongjmp+32>: mov %esi,0x4(%esp)
0xb7ead444 <siglongjmp+36>: mov %edi,(%esp)
0xb7ead447 <siglongjmp+39>: call 0xb7ead4d0
0xb7ead44c <siglongjmp+44>: mov 0x18(%edi),%eax
0xb7ead44f <siglongjmp+47>: test %eax,%eax
0xb7ead451 <siglongjmp+49>: jne 0xb7ead470 <siglongjmp+80>
0xb7ead453 <siglongjmp+51>: test %esi,%esi
0xb7ead455 <siglongjmp+53>: mov $0x1,%eax
0xb7ead45a <siglongjmp+58>: cmove %eax,%esi
0xb7ead45d <siglongjmp+61>: mov %esi,0x4(%esp)
0xb7ead461 <siglongjmp+65>: mov %edi,(%esp)
0xb7ead464 <siglongjmp+68>: call 0xb7ead490
0xb7ead469 <siglongjmp+73>: lea 0x0(%esi,%eiz,1),%esi
0xb7ead470 <siglongjmp+80>: lea 0x1c(%edi),%eax
0xb7ead473 <siglongjmp+83>: movl $0x0,0x8(%esp)
0xb7ead47b <siglongjmp+91>: mov %eax,0x4(%esp)
0xb7ead47f <siglongjmp+95>: movl $0x2,(%esp)
0xb7ead486 <siglongjmp+102>: call 0xb7ead890 <sigprocmask>
0xb7ead48b <siglongjmp+107>: jmp 0xb7ead453 <siglongjmp+51>
Can someone briefly explain me the code, or indicate where I can find the source code in the system?
Here is the i386 code for longjmp
, in the standard i386 ABI, without any crazy extensions for interaction with C++, exceptions, cleanup functions, signal mask, etc.:
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
Mostly, it restores the registers and stack as they were at the time of the corresponding setjmp()
. There is some additional cleanup required (fixing signal handling and unwinding pending stack handlers), as well as returning a different value as the apparent return value of setjmp, but restoring the state is the essence of the operation.
For it to work, the stack cannot be below the point at which setjmp was called. Longjmp is a brutish way to just forget everything that has been called below it down to the same level in the call stack (or function call nesting sequence) mostly by simply setting the stack pointer to the same frame it was when setjmp was called.
For it to work cleanly, longjmp()
calls all the exit handlers for intermediate functions, so they can delete variables, and whatever other cleanup is normally done when a function returns. Resetting the stack to a point less deep releases all the auto
variables but if one of those is a FILE *
, the file needs to be closed and the i/o buffer freed too.
I think you need to see Procedure Activation Records and Call Stacks and Setjmp.h 's jmp_buf
's structure.
Quoted from Expert C Programming: Deep C Secrets:
Setjmp saves a copy of the program counter and the current pointer to the top of the stack. This saves some initial values, if you like. Then longjmp restores these values effectively transferring control and resetting the state back to where you were when you did the save. It's termed "unwinding the stack", because you unroll activation records from the stack until you get to the saved one.
Have a look at page 153 also here.
The stackframe will be highly dependent on the machine and the executable, but the idea is the same.
In Windows X64 MASM
.code
my_jmp_buf STRUCT
_Frame QWORD ?;
_Rbx QWORD ?;
_Rsp QWORD ?;
_Rbp QWORD ?;
_Rsi QWORD ?;
_Rdi QWORD ?;
_R12 QWORD ?;
_R13 QWORD ?;
_R14 QWORD ?;
_R15 QWORD ?;
_Rip QWORD ?;
_MxCsr DWORD ?;
_FpCsr WORD ?;
_Spare WORD ?;
_Xmm6 XMMWORD ?;
_Xmm7 XMMWORD ?;
_Xmm8 XMMWORD ?;
_Xmm9 XMMWORD ?;
_Xmm10 XMMWORD ?;
_Xmm11 XMMWORD ?;
_Xmm12 XMMWORD ?;
_Xmm13 XMMWORD ?;
_Xmm14 XMMWORD ?;
_Xmm15 XMMWORD ?;
my_jmp_buf ENDS
;extern "C" int my_setjmp(jmp_buf env);
public my_setjmp
my_setjmp PROC
mov rax, [rsp] ;save ip
mov (my_jmp_buf ptr[rcx])._Rip, rax
lea rax, [rsp + 8] ;save sp before call this function
mov (my_jmp_buf ptr[rcx])._Rsp, rax
mov (my_jmp_buf ptr[rcx])._Frame, rax
;save gprs
mov (my_jmp_buf ptr[rcx])._Rbx,rbx
mov (my_jmp_buf ptr[rcx])._Rbp,rbp
mov (my_jmp_buf ptr[rcx])._Rsi,rsi
mov (my_jmp_buf ptr[rcx])._Rdi,rdi
mov (my_jmp_buf ptr[rcx])._R12,r12
mov (my_jmp_buf ptr[rcx])._R13,r13
mov (my_jmp_buf ptr[rcx])._R14,r14
mov (my_jmp_buf ptr[rcx])._R15,r15
;save fp and xmm
stmxcsr (my_jmp_buf ptr[rcx])._MxCsr
fnstcw (my_jmp_buf ptr[rcx])._FpCsr
movdqa (my_jmp_buf ptr[rcx])._Xmm6,xmm6
movdqa (my_jmp_buf ptr[rcx])._Xmm7,xmm7
movdqa (my_jmp_buf ptr[rcx])._Xmm8,xmm8
movdqa (my_jmp_buf ptr[rcx])._Xmm9,xmm9
movdqa (my_jmp_buf ptr[rcx])._Xmm10,xmm10
movdqa (my_jmp_buf ptr[rcx])._Xmm11,xmm11
movdqa (my_jmp_buf ptr[rcx])._Xmm12,xmm12
movdqa (my_jmp_buf ptr[rcx])._Xmm13,xmm13
movdqa (my_jmp_buf ptr[rcx])._Xmm14,xmm14
movdqa (my_jmp_buf ptr[rcx])._Xmm15,xmm15
xor rax,rax
ret
my_setjmp ENDP
;extern "C" void my_longjmp(jmp_buf env, int value);
public my_longjmp
my_longjmp PROC
;restore fp and xmm
movdqa xmm15,(my_jmp_buf ptr[rcx])._Xmm15
movdqa xmm14,(my_jmp_buf ptr[rcx])._Xmm14
movdqa xmm13,(my_jmp_buf ptr[rcx])._Xmm13
movdqa xmm12,(my_jmp_buf ptr[rcx])._Xmm12
movdqa xmm11,(my_jmp_buf ptr[rcx])._Xmm11
movdqa xmm10,(my_jmp_buf ptr[rcx])._Xmm10
movdqa xmm9,(my_jmp_buf ptr[rcx])._Xmm9
movdqa xmm8,(my_jmp_buf ptr[rcx])._Xmm8
movdqa xmm7,(my_jmp_buf ptr[rcx])._Xmm7
movdqa xmm6,(my_jmp_buf ptr[rcx])._Xmm6
fldcw (my_jmp_buf ptr[rcx])._FpCsr
ldmxcsr (my_jmp_buf ptr[rcx])._MxCsr
;restore gprs
mov r15, (my_jmp_buf ptr[rcx])._R15
mov r14, (my_jmp_buf ptr[rcx])._R14
mov r13, (my_jmp_buf ptr[rcx])._R13
mov r12, (my_jmp_buf ptr[rcx])._R12
mov rdi, (my_jmp_buf ptr[rcx])._Rdi
mov rsi, (my_jmp_buf ptr[rcx])._Rsi
mov rbp, (my_jmp_buf ptr[rcx])._Rbp
mov rbx, (my_jmp_buf ptr[rcx])._Rbx
;retore sp
mov rsp, (my_jmp_buf ptr[rcx])._Rsp
;restore ip
mov rcx, (my_jmp_buf ptr[rcx])._Rip; must be the last instruction as rcx modified
;return value
mov rax, rdx
jmp rcx
my_longjmp ENDP
END
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With