_ReturnAddress

本文介绍了_ReturnAddress内联函数的使用方法及其注意事项,并详细解释了如何通过内存管理结构PEB_LDR_DATA来获取调用者所在模块的名字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The _ReturnAddress intrinsic provides the address of the instruction in the calling function that will be executed after control returns to the caller.

返回调用当前函数的,下一个控制权获得者的指令.

如下列伪代码:

function A()

    addr =  _ReturnAddress() 

    return addr

end

function B()

     i = 4

    addr = A()

     i = 3 // addr == &(i = 3)

end

通常辅助另外一个函数,就获得一个Model的名字。

GetModuleNameByAddr((DWORD)pRetAddr, szModuleName, _countof(szModuleName));

{

BOOL XX::GetModuleNameByAddr(DWORD dwAddr, char *szName, UINT cch)

{

typedef struct _PEB_LDR_DATA {                          // Size = 0x24

ULONG Length;                             // 00

BOOLEAN Initialized;                        // 04

PVOID SsHandle;                           // 08

LIST_ENTRY InLoadOrderModuleList;              // 0C

LIST_ENTRY InMemoryOrderModuleList;            // 14

LIST_ENTRY InInitializationOrderModuleList;    // 1C

//  void *          EntryInProgress;                // 24

      } PEB_LDR_DATA, *PPEB_LDR_DATA;

szName[0] = 0;

void  *PEB = NULL,

                  *Flink = NULL,

                  *p = NULL;        

PEB_LDR_DATA *pLdr = NULL;

__asm

      {

mov edx,fs:[0x30]

mov PEB,edx

      }

pLdr = *(PEB_LDR_DATA **)((char *)PEB + 0x0c);

Flink = &pLdr->InLoadOrderModuleList;

p = pLdr->InLoadOrderModuleList.Flink;

__try

      {

do

            {

void *pBaseAddress = *(void **)((char *)p + 0x18);

assert(pBaseAddress && ((DWORD)pBaseAddress & 0xFFFF) == 0);

if (!pBaseAddress)

break;

wchar_t *lpwszFullName = *( ( wchar_t ** )( ( unsigned char * )p + 0x28 ) );

DWORD dwImageSize = *( ( DWORD * )( ( unsigned char * )p + 0x20 ) );

if (dwAddr >= (DWORD)pBaseAddress && dwAddr < (DWORD)pBaseAddress + dwImageSize)

                  {

wchar_t *lpwszName = lpwszFullName;

for (int i = 0; lpwszFullName[i] != 0; i++)

                        {

if (lpwszFullName[i] == L'\\')

lpwszName = lpwszFullName + i + 1;

                        }

                        ::WideCharToMultiByte(CP_ACP, 0, lpwszName, -1, szName, cch, NULL, NULL);

break;

                  }

p = *( ( void ** )p);

            } while ( Flink != p );

      }

__except(EXCEPTION_EXECUTE_HANDLER)

      {

assert(0);

      }

return szName[0] != 0;

}

}

_ReturnAddress 需要做内联属性,所以在调用前,需要

#pragma intrinsic(_ReturnAddress)

这里有个主意事项,内联函数和_ReturnAddress的返回值,如果把一个函数内联,那么_ReturnAddress就会相应的提升到上一个回溯堆栈中,

也就意味着返回地址是上一级的调用返回地址。

转载于:https://www.cnblogs.com/JefferyZhou/archive/2012/09/24/2700303.html

<think>好的,我现在需要帮助用户了解return_address函数的使用和解释。首先,我需要确定用户提到的“return_address”具体指的是什么。因为不同的编程语言和上下文中,return_address可能有不同的含义。 根据用户提供的引用内容,尤其是引用[1],里面提到返回局部变量的地址在C语言中是不安全的,但在其他语言(比如示例中的Go)可能是允许的。这可能涉及到函数返回地址的概念,或者在调试、底层编程中获取返回地址的操作。 首先,我应该检查是否存在名为return_address的标准函数或编程概念。例如,在C语言中,没有标准的return_address函数,但某些编译器(如GCC)可能提供内置函数来获取返回地址,比如__builtin_return_address。这通常用于调试或底层系统编程,用于跟踪函数调用堆栈。 另外,用户可能指的是返回指针的函数,比如函数返回某个变量的地址。这种情况下,需要注意内存管理的安全性,比如在C中返回局部变量的地址会导致悬空指针,但在Go中可能允许,如引用[1]所述。 接下来,我需要整理这些信息,分点解释return_address的不同含义和用法,包括编译器特定的函数和返回指针的函数。同时,要结合用户提供的引用内容,特别是引用[1]中关于返回局部变量地址的情况,说明不同语言的处理差异。 另外,用户可能对如何在实际编程中使用这些功能感兴趣,需要给出示例代码,并指出潜在的风险和最佳实践。例如,在C中使用__builtin_return_address的示例,以及Go中返回结构体指针的示例。 最后,生成相关问题,帮助用户进一步探索相关主题,比如调试技术、内存管理、编译器特性等。</think>### 关于return_address函数或概念的解释 在编程中,“return_address”通常有两种不同但相关的含义,具体取决于上下文: --- #### 1. **编译器内置函数:获取调用栈返回地址** - 在C/C++等低级语言中,某些编译器(如GCC)提供内置函数`__builtin_return_address`,用于获取当前函数的调用者返回地址。这常用于调试或底层系统开发。 - **语法示例**: ```c void* return_addr = __builtin_return_address(0); // 获取当前函数的返回地址 ``` - **用途**: - 调试:跟踪函数调用链,如实现栈回溯[^1] - 性能分析:分析函数调用频率 - **风险**: - 高度依赖编译器实现(非标准) - 可能引发安全漏洞(如通过地址注入代码) --- #### 2. **返回指针的函数:地址作为返回值** - 函数可以返回变量/对象的地址。此时需注意内存生命周期: ```go func createFile() *File { return &File{fd: 1, name: "test.txt"} // Go允许返回局部变量地址,编译器自动管理内存[^1] } ``` - **对比C语言**: ```c int* dangerous() { int x = 10; return &x; // 错误!x的內存在函数返回后失效 } ``` --- ### 关键差异总结 | 特性 | 编译器内置return_address | 返回地址的函数 | |--------------------|--------------------------------|-----------------------| | 作用域 | 运行时调用栈信息 | 内存地址传递 | | 内存安全 | 只读访问无风险 | 需严格管理对象生命周期 | | 典型应用场景 | 调试器、崩溃报告 | 对象工厂模式、资源共享 | --- ### 示例代码(GCC环境) ```c #include <stdio.h> void print_return_address() { void* addr = __builtin_return_address(0); printf("Caller return address: %p\n", addr); } int main() { print_return_address(); // 输出main函数中调用后的下一条指令地址 return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值