왜 변경하지 않아야합니까?
정의되지 않은 동작이기 때문입니다. C99 N1256 draft 6.7.8 / 32 "Initialization" 에서 인용 :
예 8 : 선언
char s[] = "abc", t[3] = "abc";
"일반"문자 배열 객체를 정의 s
하고t
요소가 문자열 리터럴로 초기화됩니다.
이 선언은
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
배열의 내용을 수정할 수 있습니다. 한편, 선언
char *p = "abc";
p
"pointer to char"유형으로 정의 하고 길이가 4 인 "array of char"유형의 객체를 가리 키도록 초기화합니다. 길이가 4 인 요소는 문자열 리터럴로 초기화됩니다. p
배열의 내용을 수정하는 데 사용하려고 하면 동작이 정의되지 않습니다.
그들은 어디로 갑니까?
GCC 4.8 x86-64 ELF 우분투 14.04 :
char s[]
: 스택
char *s
:
.rodata
객체 파일의 섹션
.text
읽기 및 실행 권한은 있지만 쓰기 권한은없는 오브젝트 파일 섹션이 덤프 되는 동일한 세그먼트
프로그램:
#include <stdio.h>
int main() {
char *s = "abc";
printf("%s\n", s);
return 0;
}
컴파일 및 디 컴파일 :
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
출력 내용 :
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
따라서 문자열은 .rodata
섹션에 .
그때:
readelf -l a.out
포함 (간체) :
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000704 0x0000000000000704 R E 200000
Section to Segment mapping:
Segment Sections...
02 .text .rodata
기본 링커 스크립트는 모두 덤프이 수단 .text
과 .rodata
실행하지만 수정할 수는 없습니다 세그먼트에 ( Flags = R E
). 이러한 세그먼트를 수정하려고하면 Linux에서 segfault가 발생합니다.
우리가 같은 일을한다면 char[]
:
char s[] = "abc";
우리는 얻는다 :
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
스택에 저장되고 (에 상대적으로 %rbp
) 물론 수정할 수 있습니다.