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

Arm内联汇编调用C函数报错及寄存器读取需求问题

在Android Cxxdroid中解决ARM内联汇编调用C函数及读取寄存器r0-r3的问题

一、解决BL %[p_screen]编译报错

ARM架构中,BL指令仅支持跳转到相对PC的标签,无法直接跳转到寄存器存储的函数地址。要调用寄存器中的函数地址,需改用BLX指令(Android设备基本都支持ARMv5及以上,兼容该指令)。同时,调用函数会修改lr(链接寄存器),必须将其加入clobber列表,告知编译器该寄存器会被修改。

二、实现读取r0-r3寄存器值

ARM函数调用约定中,r0-r3用于传递前4个参数,在调用_print_screen时这些寄存器的值会保留。可在_print_screen中通过内联汇编直接读取寄存器值到C变量,再打印输出。

修正后的完整代码

#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>

struct iphdr {
    uint8_t   hdrlen:4;
    uint8_t   version:4;
    uint8_t   ecn:2;       // Explicit Congestion Notification - RFC 3168
    uint8_t   dscp:6;      // DiffServ Code Point
    uint16_t  length;
    uint16_t  ident;
    uint16_t  fragoff:13;
    uint16_t  flags:3;
    uint8_t   ttl;
    uint8_t   protocol;
    uint16_t  checksum;
    uint32_t  srcip;
    uint32_t  dstip;
    uint32_t  options[ ];  // Present if hdrlen > 5
} __attribute__((__packed__));

void _print_screen(void)
{
    uint32_t r0, r1, r2, r3;
    // 内联汇编读取r0-r3寄存器值到C变量
    __asm__ volatile (
        "mov %[r0_val], r0\n"
        "mov %[r1_val], r1\n"
        "mov %[r2_val], r2\n"
        "mov %[r3_val], r3\n"
        : [r0_val] "=r" (r0),
          [r1_val] "=r" (r1),
          [r2_val] "=r" (r2),
          [r3_val] "=r" (r3)
    );
    printf("r0: 0x%x, r1: 0x%x, r2: 0x%x, r3: 0x%x\n", r0, r1, r2, r3);
}

int sum(int k, int l, int m, uint8_t n, uint32_t o, uint32_t p)
{
    int res = 0;

    __asm__ volatile (
        "cmp %[input_i], #0\n"
        "beq endrec\n"
        "sub %[input_i], %[input_i], #1\n"
        "blx %[p_screen]\n"  // 用BLX跳转到寄存器中的函数地址
        "endrec:\n"
        : [result] "+r" (res),
          [input_i] "+r" (k)  // input_i被修改,使用读写约束
        : [input_j] "r" (l), [input_k] "r" (m), [input_l] "r" (n), 
          [input_m] "r" (o), [input_n] "r" (p), [p_screen] "r" (_print_screen)
        : "lr", "r0", "r1", "r2", "r3"  // 声明被修改的寄存器
    );

    return res;
}

int main(void)
{
    struct iphdr iph;
    int d = 1;
    int e;

    iph.version = 4;
    iph.hdrlen = 5;
    iph.protocol = 3;
    // 正确转换IP地址为网络字节序32位整数
    iph.srcip = htonl(0x01010102);
    iph.dstip = htonl(0x01010101);
    
    e = sum(d, iph.version, iph.hdrlen, iph.protocol, iph.srcip, iph.dstip);
    
    return 0;
}

关键说明

  1. BLX指令的使用:替代BL实现寄存器地址的函数跳转,同时自动设置LR寄存器为返回地址。
  2. Clobber列表:补充lr及r0-r3,避免编译器优化导致的寄存器冲突。
  3. IP地址赋值修正:使用htonl将点分十进制IP转换为网络字节序的32位整数,避免字符串赋值错误。
  4. 寄存器读取逻辑:通过mov指令将寄存器值转移到C变量,实现寄存器内容的打印输出。

内容的提问来源于stack exchange,提问作者Steven Vanhaeren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 12:22:32