首页 > 解决方案 > 将字符缓冲区转换为函数指针

问题描述

我最近发现您可以在运行时将机器代码注入缓冲区中,将其转换为函数指针,然后调用它来执行缓冲区中的指令。它看起来像这样:

int main(void)
{
    char buffer[] = "\xB8\x04\x00\x00\x00\xC3";
    auto func = (int(*)())buffer;
    func();

    return 0;
}

现在,如果我不想在运行时为函数调用付费怎么办,换句话说,我想将缓冲区视为一个inline函数。

我第一次天真地尝试实现这一点是同时声明 thebufferfuncasconstexpr并将 c 样式转换替换为static_cast,尽管这似乎不起作用,因为根据 gcc,它是无效的转换。也尝试reinterpret_cast过,但显然无法在编译时评估

如果有可能实现这一点,任何想法都会受到欢迎。

标签: c++casting

解决方案


内联汇编代码可以通过asm 声明注入到 C++ 函数中。这个结构是有条件的支持和定义的实现。

在大多数实现中,asm 声明需要某种形式的符号汇编语言,而不是二进制目标代码。

asm这是在 x86 上使用 GCC的声明构造的示例。

#include <iostream>

template <int nontype>
int add(int operand)
{
    int sum;

    asm ("movl %1, %0\n\t"
         "addl %2, %0"
         : "=r" (sum)
         : "r" (operand), "r" (nontype)
         : "0");

    return sum;
}

int main()
{
    std::cout << add<42>(6) << "\n";
}

这将按预期打印 48。

请注意,gcc 的版本asm非常强大,它的语法必须超出标准规定的范围才能支持它的许多特性。其他实现可能会也可能不会提供这种灵活性(或者确实提供任何东西——有条件地支持该构造)。

函数指针和数据指针之间的转换是 C++ 中未定义的行为。实现可以用它做任何他们想做的事情。我猜想利用这种特殊形式的 UB 来复制完美的 asm 声明功能在大多数实现者的待办事项列表中是相当低的。


推荐阅读