2013-02-10 1 views
4

Assembly Primer For Hackers (Part 2) Virtual Memory Organization에 따르면 Linux 프로그램 .text 섹션은 0x0804800에서 시작하고 스택 맨은 0xbffffff에서 시작합니다. 이 숫자의 의미는 무엇입니까? 0x0000000 (또는 0x0000020 또는 0x0000040)으로 .text을 시작하면 NULL 다음 32 또는 64 비트가됩니다. 왜 스택 상단을 0xfffffff에 시작하지 않으시겠습니까?Linux 프로그램 .text 섹션이 0x0804800에서 시작하고 스택 상단이 0xbffffff에서 시작하는 이유는 무엇입니까?

답변

5

대부분의 경우, 다양한 섹션을 특정 위치에 배치 할 필요가 없습니다. 더 중요한 것은 레이아웃입니다. 요즘 스택 상단은 실제로 무작위로 지정됩니다 (here 참조).

0x08048000은 ld가 Linux/x86에서 첫 번째 PT_LOAD 세그먼트를 시작하는 기본 주소입니다. Linux/amd64의 경우 기본값은 0x400000이며 사용자 정의 링커 스크립트를 사용하여 기본값을 변경할 수 있습니다. .text 섹션이 gcc에 대한 플래그 인 -Wl,-Ttext,0xNNNNNNNN으로 시작하는 위치를 변경할 수도 있습니다. .text가 주소 0에 매핑되지 않는 이유를 이해하려면 편의상 NULL 포인터가 일반적으로 ((void *) 0)에 매핑된다는 점에 유의하십시오. 그런 다음 0 페이지가 NULL 포인터의 사용을 트랩하기 위해 액세스 할 수 없게 매핑되는 것이 유용합니다. .text가 시작되기 전에 메모리가 실제로 많은 것들에 의해 사용됩니다; 예를 들어 cat /proc/self/maps을 :

$ cat /proc/self/maps 
001c0000-00317000 r-xp 00000000 08:01 245836  /lib/libc-2.12.1.so 
00317000-00318000 ---p 00157000 08:01 245836  /lib/libc-2.12.1.so 
00318000-0031a000 r--p 00157000 08:01 245836  /lib/libc-2.12.1.so 
0031a000-0031b000 rw-p 00159000 08:01 245836  /lib/libc-2.12.1.so 
0031b000-0031e000 rw-p 00000000 00:00 0 
00376000-00377000 r-xp 00000000 00:00 0   [vdso] 
00852000-0086e000 r-xp 00000000 08:01 245783  /lib/ld-2.12.1.so 
0086e000-0086f000 r--p 0001b000 08:01 245783  /lib/ld-2.12.1.so 
0086f000-00870000 rw-p 0001c000 08:01 245783  /lib/ld-2.12.1.so 
08048000-08051000 r-xp 00000000 08:01 2244617 /bin/cat 
08051000-08052000 r--p 00008000 08:01 2244617 /bin/cat 
08052000-08053000 rw-p 00009000 08:01 2244617 /bin/cat 
09ab5000-09ad6000 rw-p 00000000 00:00 0   [heap] 
b7502000-b7702000 r--p 00000000 08:01 4456455 /usr/lib/locale/locale-archive 
b7702000-b7703000 rw-p 00000000 00:00 0 
b771b000-b771c000 r--p 002a1000 08:01 4456455 /usr/lib/locale/locale-archive 
b771c000-b771e000 rw-p 00000000 00:00 0 
bfbd9000-bfbfa000 rw-p 00000000 00:00 0   [stack] 

은 우리가 여기에서 보는 것은 C 라이브러리, 동적 로더 ld.so 커널 VDSO (커널 커널에 약간의 인터페이스를 제공 매핑 동적 코드 라이브러리)입니다.힙의 시작도 임의로 지정됩니다.

3

중요성은별로 없습니다.

스택은 일반적으로 하위 주소로 확장되므로 높은 주소에 배치하고 하위 주소로 확장 할 수있는 여지가 다소 있습니다 (필수는 아님).

프로그램 섹션에 주소 0을 사용하지 않는 것에 대해서는 여기에 약간의 논리가 있습니다. 첫째, 많은 소프트웨어가 NULL에 대해 0을 사용합니다. 이는 C 및 C++에서 합법적이지 않은 잘못된 포인터이며 역 참조하면 안됩니다. 많은 소프트웨어에는 실제로 포인터 유효성 검사없이 주소 0에서 메모리를 읽거나 쓰려고하는 버그가 있습니다. 주소 0 주변의 메모리 영역을 프로그램에 액세스 할 수 없도록 만들면 이러한 버그 중 일부를 발견 할 수 있습니다 (프로그램이 중단되거나 디버거에서 중지됨). 또한 NULL은 유효한 유효하지 않은 포인터이므로 해당 주소에 데이터 나 코드가 없어야합니다 (있는 경우 포인터를 NULL과 구별 할 수 없습니다).

x86 플랫폼에서 주소 0의 메모리는 일반적으로 가상 주소에서 실제 주소로 변환하여 액세스 할 수 없게됩니다. 페이지 테이블은 가상 주소 0에 대한 항목이 실제 메모리 페이지에 의해 백업되지 않도록 설정되고 페이지는 일반적으로 소수의 바이트가 아니라 크기가 4KB입니다. 그래서 주소 0을 꺼내면 1에서 4095까지의 주소를 가져옵니다. 주소 0에서 4KB 이상의 주소 공간을 가져 오는 것도 합리적입니다. 그 이유는 C 및 C++의 구조에 대한 포인터입니다. NULL 구조체에 대한 포인터를 가질 수 있으며 역 참조 할 때 포인터에 포함 된 주소 (0)에 액세스하려는 구조체 멤버와 구조체의 시작 부분 사이의 거리를 더한 메모리 액세스가 시도됩니다 (첫 번째 멤버는 0, 나머지는 0보다 큰 값).

프로그램의 특정 주소 범위를 선택하는 데는 다른 고려 사항이있을 수 있지만 모든 주소를 말할 수는 없습니다. 운영체제는 프로그램 자체에 몇 가지 프로그램 관련 자료 (데이터 구조)를 유지하려고 할 수 있습니다. 따라서 주소 공간의 액세스 가능 부분 끝에있는 고정 위치를 사용하는 것이 어떻습니까?

+1

모두 의미가 있지만, 이것은 'NULL'(0x0004096 대 0x804800)을 넘어선 200 배입니다. 또한 메모리의 리터럴 상단 (0xfffffff)에서 스택이 시작되지 않는 이유를 언급하지 않았습니다. –

+0

.text가 그만큼 높은 이유를 알지 못합니다. 하지만 왜 그럴 수 없습니까? 마지막 단락에서 스택 위치를 처리했습니다. –

+1

일반적으로 0xC0000000 이상의 주소는 32 비트 Linux 커널에서 사용됩니다. 일반적으로 사용자 모드에서이 주소 범위에 액세스하려고하면 seg 오류가 발생합니다. – Dipstick