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; }
关键说明
- BLX指令的使用:替代BL实现寄存器地址的函数跳转,同时自动设置LR寄存器为返回地址。
- Clobber列表:补充
lr及r0-r3,避免编译器优化导致的寄存器冲突。 - IP地址赋值修正:使用
htonl将点分十进制IP转换为网络字节序的32位整数,避免字符串赋值错误。 - 寄存器读取逻辑:通过
mov指令将寄存器值转移到C变量,实现寄存器内容的打印输出。
内容的提问来源于stack exchange,提问作者Steven Vanhaeren
相关产品推荐
相关产品推荐

