__builtin_addressof

__builtin_addressof

__builtin_addressof是由Richard Smith提交到clang中的,提交的patch为Add a __builtin_addressof that performs the same functionality as the built-in,commit message如下:

Add a __builtin_addressof that performs the same functionality as the built-in
& operator (ignoring any overloaded operator& for the type). The purpose of
this builtin is for use in std::addressof, to allow it to be made constexpr;
the existing implementation technique (reinterpret_cast to some reference type,
take address, reinterpert_cast back) does not permit this because
reinterpret_cast between reference types is not permitted in a constant
expression in C++11 onwards.

从commit message中可以看出来,__builtin_addressof()主要是作为std::addressof的”加强版本”,可用于constexpr的场景。

std::addressof

std::addressof是c++11提供的模板函数,用于获取左值表达式的地址。std::addressof的声明如下:

  • template< class T >
    T* addressof(T& arg) noexcept; (since C++11) (until C++17)
  • template< class T >
    constexpr T* addressof(T& arg) noexcept; (since C++17)
  • template < class T>
    const T* addressof(const T&&) = delete; (2) (since C++17)

1) Obtains the actual address of the object or function arg, even in presence of overloaded operator&
2) Rvalue overload is deleted to prevent taking the address of const rvalues.
The expression std::addressof(E) is a constant subexpression, if E is an lvalue constant subexpression.

其中std::addressof的存在是为了应对重载operator&的情况,能够保证获取到正确的地址。而且自从C++17开始,标准规定当std::addressof的参数lvalue constant expression的时候,std::addressof的结果也必须是constant subexpression。std::addressof的可能实现如下:

template< class T >
T* addressof(T& arg) 
{
    return reinterpret_cast<T*>(
               &const_cast<char&>(
                  reinterpret_cast<const volatile char&>(arg)));
}

注意reinterpret_cast<>不允许用于constant expression,且返回值不是constant expression,所以std::addressof的典型实现不能用于 constant expression。

Only the following conversions can be done with reinterpret_cast, except when such conversions would cast away constness or volatility.

对于此有两个问题:

  • reinterpret_cast为什么不能用于constant expression
  • std::addressof的典型实现是怎么操作的?

对于第一个问题,我不是C++ lawyer,暂时无法回答。一些相关资料见:

对于第二个问题,std::addressof的典型实现分为三步,分别是:

  • reinterpret_cast< const volatile char&>(arg)
  • &const_cast< char&>( reinterpret_cast< const volatile char&>(arg)))
  • reinterpret_cast< T*>( &const_cast< char&>(reinterpret_cast< const volatile char&>(arg)))

第一步就是将T&转换成为 const volatile char&。主要原因是std::addressof为了规避对operator&的重载,必须选择一个内置类型进行转换(内置类型没有重载operator&),然后才能安全使用的operator&来获取其地址。这里选择char的原因是,charweakest alignmentreinterpret_cast<>alignment有要求,To-Type的alignment不能比From-Type更stricter(larger),见9.2 reinterpret_cast

The weakest alignment (the smallest alignment requirement) is the alignment of char, signed char, and unsigned char, which equals 1; the largest fundamental alignment of any type is the alignment of std::max_align_t. [Alignment
]

另外由于reinterpret_cast<>不能去掉constness,所以使用const volatile char&来保证转换成功。

第二步就是使用const_cast<>合法地去掉constness。然后此时就可以安全地使用operator&获取地址了。

第三步就是将该地址再转换为原来的类型。

StackOverflow上有一篇相关的问题,见Implementation of addressof

介绍完addressof相关的内容,下面言归正传,由于从c++17开始std::addressof支持constant expression,所以现在libcxx中的std::addressof在c++17开始直接由__builtin_addressof实现,相关patch见Make std::addressof constexpr in C++17 (Clang only).

void&

这篇博客的初衷就是工作当中遇到了在clang编译__builtin_addressof的时候出现的语义分析时的错误,错误与void&相关。__builtin_addressof的函数原型如下,参数类型就是void&。但是在编码过程中是不可能出现void&的,见Why is it impossible to have a reference-to-void?
。而__builtin_addressof能够编译通过的原因是,它有自己的语义分析逻辑,针对__builtin_addressofhasCustomTypechecking为true。

BUILTIN(__builtin_addressof, "v*v&", "nct")

更多内容参见More C++ Idioms/Address Of

以上代码是一个JavaScript函数`userland()`的实现。该函数包含了一些操作和变量定义,下面对其中的关键部分进行解释: 1. `p`是一个对象,它包含了一些方法和属性。这些方法和属性用于执行一些特定的操作,如执行ROP(Return-Oriented Programming)链、动态分配内存、字符串处理等。 2. `textArea`是一个变量,它表示一个TextArea元素对象。 3. `textAreaVtPtr`是一个变量,它存储了`textArea`对象的vtable地址。 4. `textAreaVtable`是一个变量,它存储了vtable的地址。 5. `webKitBase`是一个变量,它存储了WebKit内存基址的值。通过读取vtable的第一个入口的地址并减去偏移量`OFFSET_wk_vtable_first_element`计算得出。 6. `libSceLibcInternalBase`是一个变量,它存储了`libSceLibcInternal.so`库的基址。通过解析WebKit中的导入函数`memset`的地址,然后减去偏移量`OFFSET_libcint_memset`计算得出。 7. `libKernelBase`是一个变量,它存储了`libkernel.so`库的基址。通过解析WebKit中的导入函数`__stack_chk_fail`的地址,然后减去偏移量`OFFSET_lk___stack_chk_fail`计算得出。 8. `webKitRequirementBase`是一个变量,它存储了WebKit的需求库`libps4.sprx`的基址。通过解析WebKit中的导入函数`psl_builtin`的地址,然后减去偏移量`OFFSET_WKR_psl_builtin`计算得出。 9. `wk_gadgetmap`和`wkr_gadgetmap`是两个映射对象,分别存储了WebKit和WebKit需求库的gadget(指令序列)和其对应的地址。这些gadget可以用于构建ROP链。 10. 在循环中,将gadget与其对应的地址添加到全局对象`window.gadgets`中。 总体来说,以上代码是在执行一系列操作来获取和计算一些重要的地址,为后续的ROP链构建做准备。ROP链是一种利用程序中已有的代码片段(gadget)来实现特定功能的技术。这段代码通过解析WebKit中的导入函数地址来获取库的基址,并根据预先定义的gadget映射,将它们添加到全局对象中以备后续使用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值