.BSS 섹션 제로 초기화 된 변수는 ELF 파일의 공간을 차지합니까?
문제
내가 올바르게 이해하면 .bss
ELF 파일의 섹션은 초기화 된 변수에 대한 공간을 할당하는 데 사용됩니다. 우리의 도구 체인은 ELF 파일을 생성하므로 내 질문은 다음과 같습니다. .bss
섹션은 실제로 모든 0을 포함해야합니까? 예를 들어, 글로벌 10 메가 바이트 어레이를 할당 할 때 엘프 파일에서 10 메가 바이트의 0을 초래할 때 끔찍한 공간 낭비가 보입니다. 여기서 내가 무엇을 잘못보고 있습니까?
해결책
엘프와 함께 일한 이래로 시간이 지났습니다. 그러나 나는 여전히이 것들을 기억한다고 생각합니다. 아니요, 그것은 물리적으로 그 제로를 포함하지 않습니다. ELF 파일 프로그램 헤더를 살펴보면 각 헤더에 두 가지 숫자가 표시됩니다. 하나는 파일의 크기입니다. 다른 하나는 가상 메모리에 할당 될 때 섹션과 같이 크기입니다 (readelf -l ./a.out
):
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00454 0x00454 R E 0x1000
LOAD 0x000454 0x08049454 0x08049454 0x00104 0x61bac RW 0x1000
DYNAMIC 0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW 0x4
NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
유형의 헤더 LOAD
파일이 실행을 위해로드 될 때 가상 메모리에 복사 된 것입니다. 다른 헤더에는 필요한 공유 라이브러리와 같은 다른 정보가 포함되어 있습니다. 보시다시피, FileSize
그리고 MemSiz
포함 된 헤더의 경우 크게 다릅니다 bss
섹션 (두 번째 LOAD
하나):
0x00104 (file-size) 0x61bac (mem-size)
이 예제 코드 :
int a[100000];
int main() { }
ELF 사양에 따르면 밈 크기가 파일 크기보다 크다는 세그먼트의 일부는 가상 메모리에서 0으로 채워져 있다고합니다. 두 번째 섹션 매핑에서 세그먼트 LOAD
헤더는 다음과 같습니다.
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
그래서 거기에는 다른 섹션도 있습니다. C ++ 생성자/소멸자의 경우. Java도 마찬가지입니다. 그런 다음 사본이 포함되어 있습니다 .dynamic
동적 링크에 유용한 섹션 및 기타 물건 (이것은 다른 것들 중에 필요한 공유 라이브러리를 포함하는 장소라고 생각합니다). 그 후 .data
초기화 된 글로벌 및 로컬 정적 변수를 포함하는 섹션. 결국, .bss
파일 크기가 커버되지 않기 때문에로드 타임에 0에 의해 채워진 섹션이 나타납니다.
그건 그렇고, 당신은 어떤 출력 섹션이 특정 기호를 사용하여 배치 될 것인지 확인할 수 있습니다. -M
링커 옵션. GCC의 경우 사용합니다 -Wl,-M
옵션을 링커에 넣습니다. 위의 예는이를 보여줍니다 a
내부에 할당됩니다 .bss
. 초기화되지 않은 개체가 실제로 끝나는지 확인하는 데 도움이 될 수 있습니다. .bss
그리고 다른 곳이 아닙니다 :
.bss 0x08049560 0x61aa0
[many input .o files...]
*(COMMON)
*fill* 0x08049568 0x18 00
COMMON 0x08049580 0x61a80 /tmp/cc2GT6nS.o
0x08049580 a
0x080ab000 . = ALIGN ((. != 0x0)?0x4:0x1)
0x080ab000 . = ALIGN (0x4)
0x080ab000 . = ALIGN (0x4)
0x080ab000 _end = .
GCC는 기본적으로 공통 섹션에서 초기화되지 않은 글로벌을 기본적으로, 오래된 컴파일러와의 호환성을 위해, 여러 정의 오류없이 프로그램에서 글로벌을 두 번 정의 할 수 있도록합니다. 사용 -fno-common
GCC가 객체 파일에 .BSS 섹션을 사용하도록하려면 (어쨌든 .BSS 출력 섹션으로 들어가기 때문에 최종 링크 된 실행 가능에 차이가 없습니다. 이것은 이에 의해 제어됩니다. 링커 스크립트. 표시하십시오 ld -verbose
). 그러나 그것은 당신을 놀라게해서는 안됩니다. 그것은 단지 내부 세부 사항 일뿐입니다. GCC의 맨 페이지를 참조하십시오.
다른 팁
그만큼 .bss
ELF 파일의 섹션은 정적 데이터에 사용됩니다. 초기화되지 않았습니다 프로그래밍 방식이지만 런타임에 0으로 설정되도록 보장됩니다. 다음은 차이를 설명 할 작은 예입니다.
int main() {
static int bss_test1[100];
static int bss_test2[100] = {0};
return 0;
}
이 경우 bss_test1
에 배치됩니다 .bss
비 초기화되기 때문입니다. bss_test2
그러나에 배치됩니다 .data
많은 0과 함께 세그먼트. 런타임 로더는 기본적으로 예약 된 공간의 양을 할당합니다. .bss
그리고 사용자 랜드 코드가 실행되기 전에 Zeroes를 제출합니다.
사용 차이를 볼 수 있습니다 objdump
, nm
, 또는 유사한 유틸리티 :
moozletoots$ objdump -t a.out | grep bss_test
08049780 l O .bss 00000190 bss_test1.3
080494c0 l O .data 00000190 bss_test2.4
이것은 일반적으로 첫 번째 중 하나입니다 놀라움 그 임베디드 개발자들은 정적을 명시 적으로 0으로 초기화하지 않습니다. 런타임 로더 (보통)가이를 처리합니다. 명시 적으로 초기화하자마자 컴파일러/링커에 데이터를 실행 가능한 이미지에 포함하도록 지시합니다.
ㅏ .bss
섹션은 실행 파일에 저장되지 않습니다. 가장 일반적인 섹션 중 (.text
, .data
, .bss
), 뿐 .text
(실제 코드) 및 .data
(초기화 된 데이터)는 ELF 파일에 있습니다.
맞습니다. 썸 규칙 전용로드, TLS 세그먼트는 응용 프로그램 프로그램의 메모리를 가져 오며 REST는 동적 로더에 사용됩니다.
정적 실행 파일에 대해 BSS 섹션도 실행 공간에 공간이 제공됩니다.
로더가없는 경우 내장 응용 프로그램은 일반적입니다.
수만