Frederick Virchanza Gotham
2023-04-24 15:20:32 UTC
I've written the following C++ code as an example:
#include <cstdio> // puts
extern void LibFunc(void) noexcept(false); // likely to throw an exception
void Func(void)
{
try
{
LibFunc();
}
catch (...)
{
std::puts("caught");
}
}
gets compiled to:
.LC0:
.string "caught"
Func():
push rbx
call LibFunc()
jmp .L1
mov rdi, rax
call __cxa_begin_catch
mov edi, OFFSET FLAT:.LC0
call puts
call __cxa_end_catch
.L1:
pop rbx
ret
mov rbx, rax
call __cxa_end_catch
mov rdi, rbx
call _Unwind_Resume
There's a few things I don't understand here:
(1) Why does Func save and restore the RBX register if it never changes it? I realise that RBX is callee-saved and so you must push it onto the stack before altering it, but I don't see anywhere where it's altered.
(2) If 'LibFunc' throws an exception, how does it know where to jump back to? In normal circumstances if the function returned normally, it would jump back to the 'jmp .L1' instruction, but instead it has to jump back to one instruction after that. How does it know what offset of the return address to jump back to?
(3) I don't know why those last four lines are there. They look like unreachable code to me.
Can anyone enlighten me please?
#include <cstdio> // puts
extern void LibFunc(void) noexcept(false); // likely to throw an exception
void Func(void)
{
try
{
LibFunc();
}
catch (...)
{
std::puts("caught");
}
}
gets compiled to:
.LC0:
.string "caught"
Func():
push rbx
call LibFunc()
jmp .L1
mov rdi, rax
call __cxa_begin_catch
mov edi, OFFSET FLAT:.LC0
call puts
call __cxa_end_catch
.L1:
pop rbx
ret
mov rbx, rax
call __cxa_end_catch
mov rdi, rbx
call _Unwind_Resume
There's a few things I don't understand here:
(1) Why does Func save and restore the RBX register if it never changes it? I realise that RBX is callee-saved and so you must push it onto the stack before altering it, but I don't see anywhere where it's altered.
(2) If 'LibFunc' throws an exception, how does it know where to jump back to? In normal circumstances if the function returned normally, it would jump back to the 'jmp .L1' instruction, but instead it has to jump back to one instruction after that. How does it know what offset of the return address to jump back to?
(3) I don't know why those last four lines are there. They look like unreachable code to me.
Can anyone enlighten me please?