c++ - 将字符缓冲区转换为函数指针
问题描述
我最近发现您可以在运行时将机器代码注入缓冲区中,将其转换为函数指针,然后调用它来执行缓冲区中的指令。它看起来像这样:
int main(void)
{
char buffer[] = "\xB8\x04\x00\x00\x00\xC3";
auto func = (int(*)())buffer;
func();
return 0;
}
现在,如果我不想在运行时为函数调用付费怎么办,换句话说,我想将缓冲区视为一个inline
函数。
我第一次天真地尝试实现这一点是同时声明 thebuffer
和func
asconstexpr
并将 c 样式转换替换为static_cast
,尽管这似乎不起作用,因为根据 gcc,它是无效的转换。也尝试reinterpret_cast
过,但显然无法在编译时评估
如果有可能实现这一点,任何想法都会受到欢迎。
解决方案
内联汇编代码可以通过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 声明功能在大多数实现者的待办事项列表中是相当低的。
推荐阅读
- c# - 空响应返回 204
- scala - 避免使用 OptionT 的样板(自然变换?)
- python - 使用 pipenv install -r requirements.txt 找到“.dist-info 目录”
- delphi - ServerSocket 只接收一次
- angular-cli - 将 Angular 6 cli 构建使用 Angular/cli@1.7.4 创建的 Angular 应用程序
- git - 使用 git API 和 cURL 的 Git 分支限制
- ios - Firebase 实时数据库查询因用户身份验证后的安全规则而失败,否则工作
- python - pygame.time.wait() 使程序崩溃
- android - 日期/持续时间的 Droid API 22+ 选项(在 Kotlin 中)?
- python - 无法使用 pandas 和 xlsxwriter 将格式添加到 Excel 工作表