如何通过C内联汇编修改寄存器$rsi指向的字符串内容
解决内联汇编修改$rsi指向字符串的问题
我来帮你理清这里的问题,你之前的核心错误是对GCC内联汇编的内存寻址语法理解错了,另外还有一个容易踩的坑需要注意。
首先纠正你的语法错误
你想写汇编里的mov [rsi], my_str来修改$rsi指向的内存,但在内联汇编里错误地用了%%[rsi]——这是把寄存器当成了内联汇编的符号名来引用,而正确的内存寻址语法应该是(%%rsi),直接用括号包裹寄存器名(注意寄存器前要加两个百分号,因为内联汇编里单个百分号是留给占位符的)。
然后注意字符串的可写性
另外,你写的char *my_str = "abc123";是指向只读字符串常量的指针,如果直接尝试修改这个地址的内容,会触发段错误。所以一定要改成可写的数组形式:char my_str[] = "abc123";,这样字符串会被分配在栈上,允许修改。
正确的代码示例
下面分两种常见场景给出正确写法:
场景1:把单个值写入$rsi指向的内存
比如,把字符'X'写入$rsi指向的字符串第一个字节:
#include <stdio.h> int main() { char target_str[] = "original"; // 可写的目标字符串 char *rsi_target = target_str; // 模拟原本$rsi指向的地址 // 内联汇编:将'X'写入$rsi指向的内存 asm volatile ( "movb $'X', (%%rsi)" : // 输出列表(无输出) : "S" (rsi_target) // 把rsi_target加载到$rsi寄存器 : "memory" // 告诉编译器内存被修改,防止优化 ); printf("修改后:%s\n", target_str); // 输出 "Xriginal" return 0; }
场景2:把my_str的内容复制到$rsi指向的内存
如果你想把整个字符串复制过去,可以用rep movsb指令(适合批量复制):
#include <stdio.h> int main() { char my_str[] = "abc123"; // 源字符串(可写) char target_str[10] = {0}; // 目标字符串(可写) char *rsi_target = target_str; // 模拟原本$rsi指向的地址 char *rdi_source = my_str; // 源地址放到$rdi // 内联汇编:复制6个字节从$rdi到$rsi asm volatile ( "mov $6, %%rcx\n" // 设置复制长度为6 "rep movsb" // 循环复制,每次1字节 : : "S" (rsi_target), "D" (rdi_source) : "rcx", "memory" // 声明被修改的寄存器和内存 ); printf("复制后:%s\n", target_str); // 输出 "abc123" return 0; }
对应你最初需求的写法
如果你就是想把my_str的指针值写入$rsi指向的内存(对应你提到的mov [rsi], my_str),代码应该是:
char my_str[] = "abc123"; char *original_rsi_ptr = some_valid_memory_address; // 假设这是原本$rsi指向的地址 asm volatile ( "mov %[changed_string], (%%rsi)" : : "S" (original_rsi_ptr), [changed_string] "r" (my_str) : "memory" );
关键注意点
- 用
(%%reg)表示寄存器指向的内存,而不是%%[reg] - 必须确保目标内存是可写的,不要修改字符串常量
- 添加
volatile关键字防止编译器优化掉你的汇编代码 - 用
"memory"约束告诉编译器内存被修改,避免缓存不一致的问题
内容的提问来源于stack exchange,提问作者Justanothermatt
相关产品推荐
相关产品推荐

