programing

Linux에서 문자열 리터럴의 메모리 주소가 다른 것과 다른 이유는 무엇입니까?

yoursource 2023. 1. 25. 08:57
반응형

Linux에서 문자열 리터럴의 메모리 주소가 다른 것과 다른 이유는 무엇입니까?

문자열 리터럴은 다른 상수 및 변수(Linux OS)와 매우 다른 주소를 가지고 있다는 것을 알게 되었습니다. 선두에 0이 많이 있습니다(인쇄되지 않음).

예:

const char *h = "Hi";
int i = 1;
printf ("%p\n", (void *) h);
printf ("%p\n", (void *) &i);

출력:

0x400634
0x7fffc1ef1a4c

저장해 둔 것을 알고 있습니다..rodata실행 파일의 일부입니다.그 후 OS가 처리함으로써 리터럴이 특수한 메모리 영역(선행 0)에 도달하는 특별한 방법이 있습니까?그 메모리 장소의 장점이나 특별한 점이 있나요?

리터럴은 읽기 전용 변수이며 리터럴 풀의 개념도 있습니다.리터럴 풀이란 프로그램의 고유 리터럴의 집합으로, 참조가 하나로 병합될 때 중복 상수가 폐기됩니다.

각 소스에는 리터럴 풀이 1개씩 있으며 링크/바인드 프로그램의 정교함에 따라 리터럴 풀을 서로 나란히 배치하여 하나의 .rodata를 생성할 수 있습니다.

또한 리터럴 풀이 읽기 전용으로 보호된다는 보장도 없습니다.언어를 사용하는 컴파일러 설계에서는 그렇게 취급합니다.

내 코드 조각을 생각해 봐나는 가질 수 있었다.

const char *cp="hello world";
const char *cp1="hello world";

좋은 컴파일러는 이 소스 코드 내에서 읽기 전용 리터럴 cp, cp1이 동일한 문자열을 가리키고 있음을 인식하고 cp1이 cp의 리터럴을 가리키도록 하여 두 번째 리터럴을 폐기합니다.

한 점만 더.리터럴 풀은 256바이트의 배수 또는 다른 값일 수 있습니다.풀 데이터가 256바이트 미만일 경우 슬랙은 16진수 0으로 채워집니다.

다른 컴파일러는 공통 개발 표준을 따르며 C로 컴파일된 모듈을 어셈블리 언어 또는 다른 언어로 컴파일된 모듈과 링크할 수 있습니다.2개의 리터럴수영장은 .rodata에 연속적으로 배치됩니다.

Linux에서 프로세스 메모리를 배치하는 방법은 다음과 같습니다(http://www.thegeekstuff.com/2012/03/linux-processes-memory-layout/):

Linux 프로세스 메모리 레이아웃

.rodata 섹션은 Initialized Global Data 블록의 쓰기 금지 하위 섹션입니다.(ELF 실행 파일이 .data지정하는 섹션은 0이 아닌 값으로 초기화된 쓰기 가능한 글로벌에 대한 쓰기 가능한 섹션입니다.0으로 초기화된 쓰기 가능한 전역은 .bss 블록으로 이동합니다.여기서 글로벌이란 배치에 관계없이 글로벌 변수와 모든 정적 변수를 의미합니다.)

사진은 당신의 주소의 숫자를 설명해 줄 것입니다.

더 자세히 조사하려면 Linux에서 실행 중인 프로세스의 메모리 레이아웃을 설명하는 /proc/$pid/maps 가상 파일을 검사할 수 있습니다.예약된(도트로 시작하는) ELF 섹션 이름은 얻을 수 없지만 메모리 보호 플래그를 보면 메모리 블록이 생성된 ELF 섹션의 이름을 추측할 수 있습니다.예를 들어 실행 중

$ cat /proc/self/maps #cat's memory map

준다

00400000-0040b000 r-xp 00000000 fc:00 395465                             /bin/cat
0060a000-0060b000 r--p 0000a000 fc:00 395465                             /bin/cat
0060b000-0060d000 rw-p 0000b000 fc:00 395465                             /bin/cat
006e3000-00704000 rw-p 00000000 00:00 0                                  [heap]
3000000000-3000023000 r-xp 00000000 fc:00 3026487                        /lib/x86_64-linux-gnu/ld-2.19.so
3000222000-3000223000 r--p 00022000 fc:00 3026487                        /lib/x86_64-linux-gnu/ld-2.19.so
3000223000-3000224000 rw-p 00023000 fc:00 3026487                        /lib/x86_64-linux-gnu/ld-2.19.so
3000224000-3000225000 rw-p 00000000 00:00 0
3000400000-30005ba000 r-xp 00000000 fc:00 3026488                        /lib/x86_64-linux-gnu/libc-2.19.so
30005ba000-30007ba000 ---p 001ba000 fc:00 3026488                        /lib/x86_64-linux-gnu/libc-2.19.so
30007ba000-30007be000 r--p 001ba000 fc:00 3026488                        /lib/x86_64-linux-gnu/libc-2.19.so
30007be000-30007c0000 rw-p 001be000 fc:00 3026488                        /lib/x86_64-linux-gnu/libc-2.19.so
30007c0000-30007c5000 rw-p 00000000 00:00 0
7f49eda93000-7f49edd79000 r--p 00000000 fc:00 2104890                    /usr/lib/locale/locale-archive
7f49edd79000-7f49edd7c000 rw-p 00000000 00:00 0
7f49edda7000-7f49edda9000 rw-p 00000000 00:00 0
7ffdae393000-7ffdae3b5000 rw-p 00000000 00:00 0                          [stack]
7ffdae3e6000-7ffdae3e8000 r--p 00000000 00:00 0                          [vvar]
7ffdae3e8000-7ffdae3ea000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

번째 ★★★★★★★★★★★★★★.r-xp블록은 확실히 .text(비활성 코드), 첫 번째.text는 첫 번째 코드입니다.r--p.rodata의 블록과 .bss.data 다음 rw-블록(히프와 스택블록 사이는 다이내믹 링커에 의해 동적으로 링크된 라이브러리에서 로드된 블록입니다.)


주의: 표준을 준수하기 위해,int*★★★★★★에"%p"로로 합니다.(void*)그렇지 않으면 동작이 정의되지 않습니다.

문자열 리터럴에는 정적 저장 기간이 있기 때문입니다.즉, 그들은 전체 프로그램 동안 살게 된다.이러한 변수는 이른바 힙에도 스택에도 없는 특수한 메모리 위치에 저장할 수 있습니다.그 때문에, 주소의 차이가 발생합니다.

포인터의 위치는 포인터가 가리키는 위치와 다릅니다.보다 현실적인 (애플 대 애플) 비교는 다음과 같습니다.

printf ("%p\n", (void *) &h);
printf ("%p\n", (void *) &i);

될 것이다.h ★★★★★★★★★★★★★★★★★」p주소가 비슷합니다. 좀 더 가 될 수도 있어요.

static int si = 123;
int *ip = &si;
printf ("%p\n", (void *) h);
printf ("%p\n", (void *) ip);

그것을 하게 될 것이다.h ★★★★★★★★★★★★★★★★★」ip같은 메모리 영역을 가리킵니다.

printf ("%p\n", h); // h is the address of "Hi", which is in the rodata or other segments of the application.
printf ("%p\n", &i); // I think "i" is not a global variable, so &i is in the stack of main. The stack address is by convention in the top area of the memory space of the process.

언급URL : https://stackoverflow.com/questions/40677631/why-are-the-memory-addresses-of-string-literals-so-different-from-others-on-li

반응형