c 语言中对字符串常量修改的错误原因解析

对字符串常量进行修改

#include <stdio.h>
int main()
{
    char *a = "hello";	// 字符串常量
    a[0] = 'w';
    printf("%s\n", a); 
    return 0;
}

运行以上代码会出现如下错误: Segmentation fault,即段错误。

错误解析

将上述代码编译成汇编代码如下。从中可以看出,字符串常量被声明在 rodata 节,即只读数据节(read only data)。因此尝试对字符串修改,即会引发段错误。

    .section    .rodata			; 只读数据节开始
.LC0:
    .string "hello"				; 声明的字符串常量 char *a = "hello";
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $20, %esp
    movl    $.LC0, -12(%ebp)
    movl    -12(%ebp), %eax
    movb    $119, (%eax)		; 尝试对字符串修改 a[0] = 'w';
    subl    $12, %esp
    pushl   -12(%ebp)
    call    puts
    addl    $16, %esp
    movl    $0, %eax

对字符串数组进行修改

include <stdio.h>
int main()
{
    char a[]="hello";
    a[0] = 'w';
    printf("%s\n", a); 
    return 0;
}

将其编译成汇编如下,可以看出,字符串被拷贝到堆栈上,因此对其修改没有问题。

main:
    pushl   %ebp
    movl    %esp, %ebp
    movl    $1819043176, -18(%ebp)				;	$ebp-18 = "hell"
    movw    $111, -14(%ebp)						; 	$ebp-14 = "o\0"
    movb    $119, -18(%ebp)						; 	a[0] = 'w';
    subl    $12, %esp
    leal    -18(%ebp), %eax
    pushl   %eax
    call    puts
    addl    $16, %esp
    movl    $0, %eax
上一篇:逆向反汇编day1


下一篇:汇编语言