Step to UEFI (201)直接取得函数返回地址

在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

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注