在64位模式下,Microsoft Visual Studio 不支持内嵌汇编。但是编译器本身支持一些intrinsic 预定义的指令,这次就研究一下_AddressOfReturnAddress。他的作用是“提供保存当前函数的返回地址的内存位置的地址。 此地址不能用于访问其他内存位置 (例如, 函数的参数)。”【参考1】
编写一个简单的Application 验证之:
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/IoLib.h>
/**
Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
**/
void* _AddressOfReturnAddress (VOID);
#pragma intrinsic(_AddressOfReturnAddress)
void func() {
void* pvAddressOfReturnAddress = _AddressOfReturnAddress();
Print(L"%lx\n", pvAddressOfReturnAddress);
Print(L"%lx\n", *((void**) pvAddressOfReturnAddress));
Print(L"%lx\n", _ReturnAddress());
}
/***
Print a welcoming message.
Establishes the main structure of the application.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
CpuBreakpoint();
func();
return(0);
}
运行结果如下(NT32环境)
为了便于观察我们在代码中使用 CPU BreakPoint 触发中断用 VS2015进行调试:1.触发中断
2. 从Break 中返回,call 到void func()
可以看到,当前处于call func() 的指令下,他的下一条地址是 0x1BE56C75638。和运行的结果显示一样,因此就是说可以用_AddressOfReturnAddress得到当前的函数返回的地址(就是调用语句的下一条指令)。
查看对应的汇编语句,这是通过直接将堆栈中保存的值取出来实现的。
; COMDAT func
_TEXT SEGMENT
pvAddressOfReturnAddress$ = 32
__$ReturnAddr$ = 56
func PROC ; COMDAT
; 15 : void func() {
$LN3:
00000 48 83 ec 38 sub rsp, 56 ; 00000038H
; 16 : void* pvAddressOfReturnAddress = _AddressOfReturnAddress();
00004 48 8d 44 24 38 lea rax, QWORD PTR __$ReturnAddr$[rsp]
00009 48 89 44 24 20 mov QWORD PTR pvAddressOfReturnAddress$[rsp], rax
; 17 : Print(L"%lx\n", pvAddressOfReturnAddress);
0000e 48 8b 54 24 20 mov rdx, QWORD PTR pvAddressOfReturnAddress$[rsp]
00013 48 8d 0d 00 00
00 00 lea rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
0001a e8 00 00 00 00 call Print
; 18 : Print(L"%lx\n", *((void**) pvAddressOfReturnAddress));
0001f 48 8b 44 24 20 mov rax, QWORD PTR pvAddressOfReturnAddress$[rsp]
00024 48 8b 10 mov rdx, QWORD PTR [rax]
00027 48 8d 0d 00 00
00 00 lea rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
0002e e8 00 00 00 00 call Print
; 19 : Print(L"%lx\n", _ReturnAddress());
00033 48 8b 44 24 38 mov rax, QWORD PTR __$ReturnAddr$[rsp]
00038 48 8b d0 mov rdx, rax
0003b 48 8d 0d 00 00
00 00 lea rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
00042 e8 00 00 00 00 call Print
; 20 : }
00047 48 83 c4 38 add rsp, 56 ; 00000038H
0004b c3 ret 0
func ENDP
完整的代码下载:
参考:
1. https://docs.microsoft.com/zh-cn/cpp/intrinsics/addressofreturnaddress?view=vs-2017