7

좋아요. 나는 멍청한 학생 질문을 약간 가지고 있습니다.컴파일러는 메모리에 코드를 어떻게 배열합니까?

그래서 스택에 서브 루틴 호출이 포함되어 있고 힙에 가변 길이 데이터 구조가 포함되어 있고 전역 정적 변수가 영구 메모리 위치에 할당되어 있다는 사실을 잘 알고 있습니다.

하지만 이론적 인 수준에서는 어떻게 작동합니까?

컴파일러는 주소 0에서 주소 무한대까지 전체 메모리 영역을 갖고 있다고 가정합니까? 그런 다음 물건 할당을 시작하십시오.

그리고 지침, 스택 및 힙은 어디에 레이아웃됩니까? 메모리 영역의 상단, 메모리 영역의 끝에서?

그러면 가상 메모리는 어떻게 작동합니까? 가상 메모리는 프로그램에 투명합니까?

바지 랜드 질문에 대해 유감이지만 프로그래밍 언어 구조를 사용하고 있으며이 영역을 계속 언급하고 있으며이를 좀 더 실용적인 수준에서 이해하고자합니다.

많은 것이 미리 있습니다!

+0

신속한 후속 조치를 요청할 수 있습니까? 함수를 호출하고, 로컬 변수를 만들고, 컴파일 할 때 프로그램에 포함 된 스택에 추가하는 기본 기계류입니까? 또는 기계가 운영 체제의 일부입니까? –

답변

5

포괄적 인 설명은 아마도이 포럼의 범위를 벗어날 것입니다. 전체 텍스트는 주제에 사용됩니다. 그러나 단순한 수준에서 보면이 방법으로 볼 수 있습니다.

컴파일러는 코드를 메모리에 배치하지 않습니다. 그것은 자신에게 전체 메모리 영역을 가지고 있다고 가정합니다. 컴파일러는 객체 파일의 심볼이 일반적으로 오프셋 0에서 시작하는 객체 파일을 생성합니다.

링커는 객체 파일을 함께 가져 와서 심볼을 링크 된 객체 내의 새 오프셋 위치에 연결하고 실행 파일 형식을 생성합니다 .

링커는 메모리에 코드를 배치하지 않습니다. 코드 및 데이터를 실행 코드 명령어의 경우 .text, 전역 변수 및 문자열 상수의 경우 .data으로 분류 된 섹션에 패키지화합니다. (다른 목적으로 다른 섹션도 있습니다.) 링커는 운영 체제 로더에게 심볼 재배치에 대한 힌트를 제공하지만 로더는이를 강요 할 필요가 없습니다.

실행 파일을 구문 분석하고 코드 및 데이터가 메모리에 배치되는 위치를 결정하는 운영 체제 로더입니다. 위치는 전적으로 운영 체제에 따라 다릅니다. 일반적으로 스택은 프로그램 명령어 및 데이터보다 높은 메모리 영역에 위치하며 하향으로 커집니다.

각 프로그램은 전체 주소 공간을 가지고 있다는 가정하에 컴파일/링크됩니다. 이것은 가상 메모리가 들어오는 곳입니다. 프로그램에 완전히 투명하며 운영 체제에 의해 전적으로 관리됩니다.

일반적으로 가상 메모리는 주소 0부터 플랫폼에서 지원하는 최대 주소 (무한하지 않음)까지입니다. 이 가상 주소 공간은 운영 체제에 의해 커널 주소 지정 가능 공간 및 사용자 주소 지정 가능 공간으로 분할됩니다. 가상의 32 비트 OS에서, 0x80000000 이상의 주소는 운영 체제 용으로 예약되어 있으며 아래 주소는 프로그램에서 사용하기위한 것입니다. 프로그램이이 파티션 위의 메모리에 액세스하려고하면 중단됩니다.

운영 체제는 스택이 가장 높은 주소 지정 가능한 사용자 메모리에서 시작하여 훨씬 낮은 주소에있는 프로그램 코드로 증가한다고 결정할 수 있습니다.

일반적으로 힙의 위치는 프로그램을 빌드 한 런타임 라이브러리에 의해 관리됩니다. 프로그램 코드 및 데이터 다음에 사용 가능한 다음 주소부터 시작할 수 있습니다.

+0

이것은 아주 좋습니다. 정확히 찾고있었습니다. 이 사이트의 좋은 사이트/책에 대한 권장 사항은 무엇입니까? 나는 심지어 무엇을 google에 알지 않는다. 구문 분석 트리를 코드로 변환 할 때 구문 분석 트리를 의미하는 것이 아니지만이 모든 것들이 실제로 낮은 수준에서 어떻게 작동하는지 더 자세히 설명합니다. –

+0

"Windows 메모리 레이아웃"에 대한 Google 검색이 시작하는 것이 좋습니다. 이 링크는 첫 페이지에 나타나며 매우 유익한 것으로 보입니다 : [기억에있는 프로그램의 해부학] (http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory) . 여기에서 당신은 아마 Google에 몇몇 다른 개념을 찾아 낼 수 있었다. –

+0

안녕하세요. 다시 한번 감사드립니다. –

1

다릅니다.

처음부터 시작해야하는 부트 로더를 컴파일하는 경우 전체 메모리를 갖고 있다고 가정 할 수 있습니다.

한편, 응용 프로그램을 컴파일하는 경우 전체 메모리가 있다고 가정 할 수 있습니다.

작은 차이점은 첫 번째 경우에는 모든 실제 메모리가 있음을 의미합니다. 부트 로더로서 RAM에 아직 다른 것은 없습니다. 두 번째 경우에는 메모리에 OS가 있지만 일반적으로 가상 메모리를 설정하여 전체 주소 공간이 사용자에게 있음을 나타냅니다. Usuaully 당신은 여전히 ​​실제 메모리를 OS에 요청해야합니다.

후자는 OS가 몇 가지 규칙을 부과한다는 것을 의미합니다. 예 : OS는 프로그램의 첫 번째 명령이 어디에 있는지 알고 싶어합니다. 간단한 규칙은 프로그램이 항상 주소 0에서 시작하므로 C 컴파일러가 int main()을 넣을 수 있습니다. OS는 일반적으로 스택이 어디에 있는지 알고 싶어하지만 이것은 이미 더 유연한 규칙입니다. "힙 (heap)"에 관한 한 OS는 정말로 신경 쓸 수 없다.

+0

감사! 따라서 내가 본 자신을 위해 전체 기억이 있다고 가정하는 것이 안전합니다. –

2

많은 주제가있는 열린 질문입니다.

일반적인 컴파일러 -> 어셈블러 -> 링커 툴체인을 가정합니다. 컴파일러는 전체적으로 많이 알지 못합니다. 단순히 스택 관련 항목을 인코딩합니다. 스택이 얼마나 많은지 또는 어디에 있는지 신경 쓰지 않습니다. 스택의 목적/아름다움입니다. 당신이

gcc hello.c -o hello 

바이너리 유틸리티의 설치가있을 때 컴파일러는 어셈블러가 객체로 조립 어셈블러를 생성 한 후 링커는, 그것을 메모리 공간의 세부 사항을 말해 어떤 맛 또는 명령 행 인수의 정보 링커 스크립트 소요 타겟 (윈도우, 맥, 리눅스, 당신이 무엇을하고 있든간에)에 맞춘 기본 링커 스크립트. 그리고 그 스크립트는 프로그램 공간이 시작되는 곳에 대한 정보를 포함하고 거기에서부터 힙 (텍스트, 데이터 및 bss 다음)을 어디에서 시작해야 하는지를 알고 있습니다. 스택 포인터는 해당 링커 스크립트에 의해 설정되거나 os가 다른 방식으로 관리합니다. 그리고 그것은 스택을 정의합니다.

windows와 linux, mac 및 bsd 랩톱 또는 데스크탑 컴퓨터가 가지고있는 mmu가있는 운영 체제의 경우 0x0000부터 시작하는 자체 주소 공간이 있다고 가정하면 각 프로그램이 컴파일됩니다. 프로그램은 0x0000에서 실행을 시작하기 위해 링크되어 있으며 운영 체제 규칙에 따라 운영 체제에 따라 다르며 일부는 예를 들어 0x8000에서 시작합니다.

프로그램의 관점에서 보면 하나의 선형 주소 공간이있는 응용 프로그램의 경우 .text와 .data 또는 .bss 중 하나 일 가능성이 높습니다. 그런 다음 힙이 어느 시점에서 정렬됩니다 그 후. 그러나 스택은 일반적으로 높게 설정되어 작동하지만 프로세서 및 운영 체제에 따라 다를 수 있습니다. 그 스택은 일반적으로 세계의 프로그램보기 내에서 메모리의 최상위에 있습니다.

가상 메모리는 응용 프로그램이 일반적으로 알지 못하거나 가상 메모리를 신경 쓰지 않는 모든 것에 보이지 않습니다. 응용 프로그램이 명령어를 가져 오거나 데이터 전송을 수행하는 경우 운영 체제에 의해 구성되고 가상과 실제간에 변환되는 하드웨어를 통과합니다.mmu가 공간을 물리적 주소로 매핑하지 않았 음을 의미하는 오류가 표시되면 때때로 의도적이어서 "가상 메모리"라는 용어를 다른 용도로 사용할 수 있습니다. 이 두 번째 정의는 예를 들어 운영 체제가 메모리의 다른 부분을 가져갈 수 있습니다. 예를 들어 다른 부분을 하드 디스크로 옮기고 그곳에 다른 부분을 표시 한 다음 청크에 일부 RAM이있는 것으로 표시합니다 당신은 당신이 당신이 다른 누군가에게서 가지고 가야 한 ㄴ다는 것을 당신이 모른 약간 숫양으로 중단되었다는 것을 모르는 상태에서 실행합니다. 귀하의 응용 프로그램은 디자인에 의해이 사실을 알기를 원하지 않으며, 단지 실행하고 싶어합니다. 운영 체제는 물리적 메모리 관리와 가상 주소 공간을 제공하는 mmu를 처리합니다 ...

처음에는 나중에 마이크로 컨트롤러, qemu, raspberry pi, beaglebone 등으로 mmu를 사용하지 않고 베어 메탈 프로그래밍을 조금 할 수있었습니다. 컴파일러, 링커 스크립트 및 mmu 구성 모두로 손을 더럽힐 수있었습니다. x86이 아닌 팔이나 밉스 (mips)를 사용하면 삶을 편하게 할 수 있습니다. 전반적인 큰 그림은 모두 대상을 가로 질러 직접 변환됩니다.

+0

감사합니다. 한 가지 일은 어셈블리에서 변수를 저장하는 주소를 선언해야하므로 컴파일러/어셈블리 생성기가 자신의 전체 주소 공간을 사용한다고 가정하고 있다고 생각했습니다. –