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이 있음)에있게됩니까? 해당 메모리 위치의 장점이 있습니까? 아니면 특별한 점이 있습니까?
다음은 Linux에서 프로세스 메모리를 배치하는 방법입니다 ( http://www.thegeekstuff.com/2012/03/linux-processes-memory-layout/ ).
.rodata 섹션의 쓰기 금지 조항이다 초기화 된 글로벌 데이터 블록. ( 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 (실행 코드), .rodata 의 첫 번째 r--p
블록 , .bss 및 .data 의 다음 rw-- 블록에서 왔습니다 . (힙과 스택 블록 사이에는 동적 링커에 의해 동적으로 연결된 라이브러리에서로드 된 블록이 있습니다.)
Note: To comply with the standard, you should cast the int*
for "%p"
to (void*)
or else the behavior is undefined.
That's because string literals have static storage duration. That is, they will live during the whole program. Such variables may be stored in a special memory location which is neither on the so called heap nor the stack. Hence the difference in addresses.
Remember that where a pointer is is different from where a pointer points to. A more realistic (apples-to-apples) comparison would be
printf ("%p\n", (void *) &h);
printf ("%p\n", (void *) &i);
I suspect you will find that h
and p
have similar addresses. Or, another more-realistic comparison would be
static int si = 123;
int *ip = &si;
printf ("%p\n", (void *) h);
printf ("%p\n", (void *) ip);
I suspect you'll find that h
and ip
point to a similar region of memory.
Consider that literals are read-only variables and as well, there is a concept of a literal pool. What the literal pool is is a collection of the program's unique literals, where duplicate constants are discarded as references are merged into one.
There is one literal pool for each source, and depending on the sophistication of the link / bind program, literal pools can be placed next to each other to create one .rodata.
There is also no guarantee that the literal pool is read-only protected. Language though compiler designs treat it as so.
Consider my code fragment. I could have
const char *cp="hello world";
const char *cp1="hello world";
The good compiler will recognize that within that source code, the read-only literals cp, cp1,are pointing to identical strings, and will make cp1 point to cp's literal, discarding the second one.
One more point. The literal pool may be a multiple of 256bytes or different value. If the pool data is less than 256 bytes, the slack will be padded with hex zeros.
Different compilers, follow common development standards, permitting a module compiled with C, to be linked with a module compiled with assembly language or other language. The two literal pools are placed consecutively in .rodata.
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.
'program tip' 카테고리의 다른 글
디버깅 중 Visual Studio : 함수를 평가하려면 모든 스레드를 실행해야합니다. (0) | 2020.11.28 |
---|---|
Angular2 : 사용자 지정 파이프를 찾을 수 없습니다. (0) | 2020.11.28 |
32 비트 컴퓨터에서-(-2147483648) =-2147483648 인 이유는 무엇입니까? (0) | 2020.11.28 |
tf.layers.conv2d 및 tf.layers.dense의 기본 커널 이니셜 라이저는 무엇입니까? (0) | 2020.11.28 |
식 트리 람다는 null 전파 연산자를 포함 할 수 없습니다. (0) | 2020.11.28 |