static int arr [10] 메모리 주소는 항상 060으로 끝납니다


17

이런 AC 프로그램이 있습니다

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

컴파일 된 프로그램을 몇 번 실행할 때 이것을 출력합니다.

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

왜 항상 060으로 끝나나요? 그리고 배열은 힙에 저장됩니까?

편집 : 나는 Linux에 있고 ASLR을 사용하고 있습니다. gcc를 사용하여 프로그램을 컴파일했습니다.


2
어떤 운영 체제입니까? 어떤 컴파일러?
Andrew Henle

2
변수는 힙에 없으며 프로그램 주소 공간의 data 또는 bss 섹션에 있습니다 ( en.wikipedia.org/wiki/Static_variable 참조) . 내 생각에 프로그램은 항상 0x1000으로 나눌 수있는 특정 경계의 메모리 주소에 배치되며 변수는 프로그램의 주소 공간에서 고정 오프셋으로 컴파일러에 의해 배치됩니다.
보도

답변:


15

주소는 ASLR (Address space layout ramdomization) 때문에 다릅니다. 이를 사용하여 이진은 가상 주소 공간의 다른 위치에 매핑 될 수 있습니다.

변수 heap는 이름과 달리 힙에 있지 않지만에 있습니다 bss. 따라서 주소 공간의 오프셋은 일정합니다.

많은 플랫폼에서 페이지는 페이지 단위로 매핑되며 4096 바이트 (16 진 : 0x1000)입니다. 이것이 주소의 마지막 3 자리 16 진수가 동일한 이유입니다.

스택 변수를 사용 하여 동일한 작업을 수행하면 스택이 다른 위치에 매핑 될뿐만 아니라 시작시 임의의 오프셋을 받기 때문에 일부 플랫폼 (즉, 최근 커널이있는 Linux)의 마지막 숫자가 다를 수 있습니다.


내가 기억하는대로 ASLR은로드 기준을 무작위로 지정합니다. 섹션 주소는 해당 주소를 기반으로합니다.
Afshin

Axel-Thobias Schreiner의 객체 지향 ANSI-C 프로그래밍에 관한 책을 사용하고 있습니다. 이 책은 1993과 같은 형식으로 작성되었습니다. 메모리 레이아웃이 다른지 알고 있습니까? 그렇지 않은 경우 왜 변수 heap가 힙이 아닐 때 변수의 이름을 지정 했을 수 있습니까?
linuxlmao

4096이 어떤 식 으로든 060으로 변환됩니까, 아니면 0x1000이 060으로 변환됩니까? 배열의 크기가 16 진수로 060으로 변환되는 것과 관련이 있다고 생각했습니다. 예를 들어 decimal
linuxlmao

2
@linuxlmao 오프셋은 예를 들어 14060이므로 여러 페이지 크기 (0x1000)를 추가하면 마지막 세 자리가 유지 060됩니다.
Ctx

4

Windows를 사용하는 경우 그 이유는 PE 구조입니다.

귀하의 heap변수에 저장되어있는 .data파일의 섹션의 주소는이 섹션의 시작을 기준으로 계산됩니다. 각 섹션은 주소에 독립적으로로드되지만 시작 주소는 페이지 크기의 배수입니다. 다른 변수가 없으므로 해당 주소는 아마도 시작 .data부분이므로 주소는 청크 크기의 배수가됩니다.

예를 들어, 이것은 컴파일 된 Windows 버전의 코드 표입니다. 섹션.text섹션은 컴파일 된 코드이며 변수를 .data포함합니다 heap. PE가 메모리에로드되면 섹션이 다른 주소로로드되고 VirtualAlloc()페이지 크기가 여러 개로 반환됩니다 . 그러나 각 변수의 주소는 이제 페이지 크기 인 섹션 시작에 상대적입니다. 따라서 항상 낮은 자리에 고정 번호가 표시됩니다. heap시작 부분 의 상대 주소는 컴파일러, 컴파일 옵션 등을 기반 으로하기 때문에 동일한 코드에서 다른 컴파일러에서 다른 번호를 볼 수 있지만 인쇄 될 때마다 고정됩니다.

코드를 컴파일 할 때 섹션 시작 후 바이트에 heap배치됩니다 . 따라서이 코드를 실행할 때마다 내 주소는로 끝납니다 .0x8B0.data0x8B0


Axel-Thobias Schreiner의 객체 지향 ANSI-C 프로그래밍에 관한 책을 사용하고 있습니다. 이 책은 1993과 같은 형식으로 작성되었습니다. 메모리 레이아웃이 다른지 알고 있습니까? 그렇지 않은 경우 왜 변수 heap가 힙이 아닐 때 변수의 이름을 지정 했을 수 있습니까?
linuxlmao

2
@linuxlmao 다를 수 있습니다. 1993 년에 Windows는 16 비트 운영 체제였으며 메모리 세분화 와 모든 종류의 혼란스러운 요소가있었습니다. 현재와 같이 32 비트 플랫 메모리 아키텍처 는 아니 었 습니다. 그러나 이러한 유형의 것들이 메모리에 프로그램 바이너리의 레이아웃에 관한 일반적인 질문을하는 것은 유용하지 않은 이유입니다. C 언어 표준 이 일반적으로 무엇을 보장하는지 이해해야 하며, 이것이 당신이 알아야 할 전부입니다. 특정 문제를 디버깅하는 경우 실제 레이아웃에 대해서만 걱정하고 디버거를 사용하십시오
Cody Gray

아니요, malloc과 함께 할당되지 않고 정적 저장 시간이 있기 때문에 구형 시스템에서도 힙에 변수를 작성하지 않아야합니다.
phuclv

@Afshin 위의 OP 의견을 처리하고 있습니다
phuclv

@phuclv 죄송합니다, 당신이 그를 언급하지 않았기 때문에, 당신이 저에게 연설하고 있다고 생각했습니다. :)
Afshin

4

heap컴파일러는 main루틴 을 시작하는 코드에서 사용하는 데이터와 같이 첫 번째 0x60 바이트에 다른 내용이 있기 때문에 아마도 0x60 바이트 오프셋에 데이터 세그먼트 를 넣었 습니다 . 그렇기 때문에“060”이 표시됩니다. 그것은 그것이 일어난 곳에 불과하며 그것에 큰 의미가 없습니다.

주소 공간 레이아웃 무작위 화는 프로그램 메모리의 다양한 부분에 사용되는 기본 주소를 변경하지만 정렬 및 기타 문제를 유발하지 않기 때문에 항상 0x1000 바이트 단위로 변경됩니다. 따라서 주소가 0x1000의 배수로 변동되는 것을 볼 수 있지만 마지막 세 자리는 변경되지 않습니다.

정의 static int heap[SOME_VAR];heap정적 저장 기간으로 정의 됩니다. 일반적인 C 구현은 힙이 아닌 일반 데이터 섹션에 저장합니다. "힙"은 동적 할당에 사용되는 메모리의 잘못된 이름입니다. ( malloc구현물은 힙에 한정되지 않고 다양한 데이터 구조와 알고리즘을 사용할 수 있기 때문에 오해 입니다. 한 구현에서 여러 메소드를 사용할 수도 있습니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.