You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Clang中通过内联汇编跳转至静态常量函数指针指向的函数?

需求与问题

已知静态常量函数指针定义如下:

#include <stdio.h>
static int (* const puts_ptr)(char const*) = &puts;

需要通过内联汇编,以puts_ptr为输入生成jmp puts指令。

GCC下的可行实现

以下代码在GCC中可以正常工作:

#include <stdio.h>
static int (* const puts_ptr)(char const*) = &puts;
void callputs(char const*X){ 
    __asm volatile ("jmp %c0\n" : : "i"(puts_ptr));
    __builtin_unreachable();
 }

它利用了i(立即数)约束和c(无美元符号输出)修饰符,但该写法无法在Clang上编译通过。

Clang的兼容性问题

Clang甚至无法处理以下简化写法:

  • 使用i约束直接传入puts:
__asm volatile ("jmp %c0\n" : : "i"(puts));
  • 使用r约束传入puts:
__asm volatile ("jmp %0\n" : : "r"(puts));

注:GCC会为第二种写法生成地址加载和寄存器间接跳转,但Clang仍无法处理。

不过在识别静态常量已知值方面,GCC和Clang表现一致,例如:

static int const x  = 42; // 也可使用enum保证常量表达式特性
static int const*const p  = &x; // 无法使用enum 
int retint_x(void){ __asm volatile ("ret;" : : "a"(x)); __builtin_unreachable(); } // 返回42; ✓; 无需从x加载
int *retptr(void){ __asm volatile ("ret;" : : "a"(p));  __builtin_unreachable();} // 返回&x ✓; 无需从p加载

编译输出:

0000000000000000 <retint_x>:
   0:   b8 2a 00 00 00          mov    $0x2a,%eax
   5:   c3                      retq   

0000000000000006 <retptr>:
   6:   b8 00 00 00 00          mov    $0x0,%eax    7: R_X86_64_32  .rodata
   b:   c3                      retq   

限制条件:不能使用constexpr(需适配纯C宏)或#define(常量由宏输出,最多使用仅支持普通整数的enum),仅要求开启优化时编译器能识别静态常量的值。

Clang适配方案

要在Clang中实现生成jmp puts指令的需求,可以采用以下两种方案:

方案1:利用%p修饰符(贴合puts_ptr输入需求)

#include <stdio.h>
static int (* const puts_ptr)(char const*) = &puts;
void callputs(char const*X){ 
    __asm volatile ("jmp %p0\n" : : "i"(puts_ptr));
    __builtin_unreachable();
 }

%p修饰符会让Clang输出不带美元符号的符号地址,符合jmp指令对直接地址的要求;开启优化后,编译器能识别puts_ptr的静态常量特性,将其解析为puts的地址,最终生成jmp puts指令。

方案2:直接引用符号(若允许跳过puts_ptr)

如果不需要严格以puts_ptr为输入,可直接编写内联汇编:

void callputs(char const*X){ 
    __asm volatile ("jmp puts\n");
    __builtin_unreachable();
 }

此方案更简洁,但未直接使用puts_ptr变量,仅适合无需绑定该变量的场景。


内容的提问来源于stack exchange,提问作者Petr Skocik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:29:57