문제

내가 올바르게 이해하면 .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 섹션도 실행 공간에 공간이 제공됩니다.

로더가없는 경우 내장 응용 프로그램은 일반적입니다.

수만

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top