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

使用x86 AT&T内联汇编修改C字符数组触发段错误的问题排查

Fixing the Segmentation Fault in Your x86 AT&T Inline Assembly Code

Great question! Let's break down exactly why your code is hitting a segmentation fault, then walk through the fixes.

The Root Cause

Your core issue is a misunderstanding of how GCC inline assembly constraints work. When you used the m constraint for string, you told the compiler that %0 represents the memory contents of the array, not its address.

Let's look at the problematic line:

mov %0, %%eax;

Since %0 is tied to a m constraint, this instruction doesn't load the address of string into eax—it loads the first byte of the array (the character 'a', ASCII 0x61) into eax. Then when you try to write to 1(%%eax), you're attempting to write to memory address 0x62, which is a low, invalid address (typically part of the OS's protected memory space). That's why you get a segmentation fault.

Additional Issues in Your Original Code

  • The =m"(string) output constraint is unnecessary: you're modifying the array in-place, not assigning a new value to the entire array variable.
  • Using "0"(string) to tie the input operand to the output operand is incorrect here, since =m marks the operand as write-only—compilers may not handle this correctly for read operations.

Fixed Code Examples

Option 1: Let the Compiler Manage the Register (Best Practice)

This approach uses a r constraint to tell the compiler to pass the address of string in a register, then we directly write to the offset:

#include <stdio.h>
int main() {
    char string[] = "ahoy";
    __asm__ volatile (
        "movb $'X', 1(%0);"  // Write 'X' to the 2nd byte of the array
        :                     // No output operands needed
        : "r"(string)        // Pass the address of string in %0
        : "memory"           // Tell compiler memory was modified
    );
    printf("%s\n", string);
    return 0;
}

Option 2: Explicitly Load the Address with lea

If you specifically want to use eax, you can use lea (load effective address) to fetch the array's address from the memory operand:

#include <stdio.h>
int main() {
    char string[] = "ahoy";
    __asm__ volatile (
        "lea %0, %%eax;"     // Load the address of string into eax
        "movb $'X', 1(%%eax);" // Write 'X' to offset 1
        :
        : "m"(string)        // Reference the array's memory
        : "memory", "eax"    // Mark eax and memory as clobbered
    );
    printf("%s\n", string);
    return 0;
}

Key Takeaways for GCC Inline Assembly

  • Use r constraints when you need to pass a pointer/address to assembly—this gives you the actual memory address in a register.
  • Use m constraints when you need to directly reference memory locations, but remember %0 will represent the contents, not the address.
  • Include "memory" in the clobber list whenever you modify memory directly—this prevents the compiler from optimizing away critical reads/writes to that memory.
  • Avoid manually specifying registers (like eax) unless you have to—letting the compiler manage registers leads to more efficient, portable code.

内容的提问来源于stack exchange,提问作者John Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:04:37