.bss 세그먼트가 필요한 이유는 무엇입니까?


120

내가 아는 것은 전역 및 정적 변수가 .data세그먼트에 저장 되고 초기화되지 않은 데이터가 .bss세그먼트에 있다는 것입니다. 내가 이해하지 못하는 것은 왜 초기화되지 않은 변수에 대한 전용 세그먼트가 있다는 것입니까? 초기화되지 않은 변수에 런타임에 할당 된 값이있는 경우 변수가 여전히 .bss세그먼트에만 존재 합니까?

다음 프로그램 a에서 .data세그먼트 b에 있고 .bss세그먼트에 있습니다. 그 맞습니까? 내 이해가 잘못된 경우 친절하게 수정하십시오.

#include <stdio.h>
#include <stdlib.h>

int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */

int main ()
{
   ;
}  

또한 다음 프로그램을 고려하십시오.

#include <stdio.h>
#include <stdlib.h>
int var[10];  /* Uninitialized so in .bss */
int main ()
{
   var[0] = 20  /* **Initialized, where this 'var' will be ?** */
}

3
BSS를 Better Save Space 로 읽을 수 있습니다 .
smwikipedia

답변:


89

그 이유는 프로그램 크기를 줄이기 위해서입니다. C 프로그램이 코드와 모든 상수가 실제 ROM (플래시 메모리)에 저장되는 임베디드 시스템에서 실행된다고 상상해보십시오. 이러한 시스템에서는 main ()이 호출되기 전에 모든 정적 저장 기간 객체를 설정하기 위해 초기 "복사"를 실행해야합니다. 일반적으로 다음 의사와 같습니다.

for(i=0; i<all_explicitly_initialized_objects; i++)
{
  .data[i] = init_value[i];
}

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

.data 및 .bss는 RAM에 저장되지만 init_value는 ROM에 저장됩니다. 하나의 세그먼트라면 ROM을 많은 0으로 채워야하므로 ROM 크기가 크게 증가합니다.

RAM 기반 실행 파일은 물론 실제 ROM이 없지만 비슷하게 작동합니다.

또한 memset은 매우 효율적인 인라인 어셈블러 일 가능성이 높으므로 시작 복사 작업이 더 빠르게 실행될 수 있습니다.


7
명확히하기 위해 .data와 .bss의 유일한 차이점은 시작시 "copy-down"이 순차적으로 실행될 수 있으므로 더 빠르다는 것입니다. 두 세그먼트로 분할되지 않은 경우 초기화는 초기화되지 않은 변수에 속하는 RAM 스팟을 건너 뛰어야하므로 시간이 낭비됩니다.
CL22 2013 년

80

.bss세그먼트는 최적화이다. 전체 .bss세그먼트는 실행중인 프로세스에서 크기를 제공하는 단일 숫자 (아마도 4 바이트 또는 8 바이트)로 설명되는 반면 .data섹션은 초기화 된 변수 크기의 합계만큼 큽니다. 따라서 .bss실행 파일을 더 작고 빠르게로드 할 수 있습니다. 그렇지 않으면 변수가 .data0으로 명시 적으로 초기화 된 세그먼트에 있을 수 있습니다 . 프로그램은 그 차이를 말하기가 어려울 것입니다. (상세하게는 객체 .bss의 주소가 .data세그먼트 에있는 경우 주소와 다를 수 있습니다 .)

첫 번째 프로그램으로, a에있을 것입니다 .data세그먼트와 b에있을 것입니다 .bss실행 파일의 세그먼트 (segment)입니다. 프로그램이로드되면 구분이 중요하지 않습니다. 런타임에 바이트를 b차지 20 * sizeof(int)합니다.

두 번째 프로그램에서는 var공간이 할당되고의 할당은 main()해당 공간 을 수정합니다. 에 대한 공간 var.bss세그먼트가 아닌 세그먼트 에 설명 .data되었지만 프로그램이 실행될 때 작동하는 방식에는 영향을주지 않습니다.


16
예를 들어, 길이가 4096 바이트 인 초기화되지 않은 버퍼를 많이 갖는 것을 고려하십시오. 이 모든 4k 버퍼가 바이너리 크기에 기여하기를 원하십니까? 그것은 많은 낭비되는 공간이 될 것입니다.
Jeff Mercado

1
@jonathen killer : 왜 전체 BS 세그먼트가 단일 숫자로 설명됩니까?
Suraj Jain

@JonathanLeffler 나는 초기화 된 모든 0 정적 변수가 bss에 있음을 의미합니다. 따라서 그 값이 0이되어서는 안됩니다. 또한 왜 .data 섹션에 공간이 주어지지 않았습니까?
Suraj Jain

2
@SurajJain : 저장된 숫자는 0으로 채워질 바이트 수입니다. 초기화되지 않은 변수가없는 한, 프로그램이로드되면 bss 섹션의 모든 바이트가 0이 되더라도 bss 섹션의 길이는 0이 아닙니다.
Jonathan Leffler

1
실행 파일의 .bss 섹션은 단순히 숫자입니다. 인 메모리 프로세스 이미지의 .bss 섹션은 일반적으로 .data 섹션에 인접한 메모리이며 종종 런타임 .data 섹션은 .bss와 결합됩니다. 런타임 메모리에는 구별이 없습니다. 때로는 bss가 시작된 위치 ( edata)를 찾을 수 있습니다 . 실제적으로 .bss는 프로세스 이미지가 완료되면 메모리에 존재하지 않습니다. 제로화 된 데이터는 .data 섹션의 단순한 부분입니다. 그러나 세부 사항은 운영
체제

15

에서 리눅스 프로그래밍 : 어셈블리 언어가 단계별 에 대해 제프 Duntemann에 의해 .DATA 섹션 :

.DATA 섹션은 초기화 된 데이터 항목의 데이터 정의가 포함되어 있습니다. 초기화 된 데이터는 프로그램이 실행되기 전에 값이있는 데이터입니다. 이러한 값은 실행 파일의 일부입니다. 실행 파일이 실행을 위해 메모리에로드 될 때 메모리에로드됩니다.

.data 섹션에 대해 기억해야 할 중요한 점은 초기화 된 데이터 항목을 많이 정의할수록 실행 파일이 커지고 실행할 때 디스크에서 메모리로로드하는 데 더 오래 걸린다는 것입니다.

그리고 .bss라고 섹션 :

프로그램 실행을 시작하기 전에 모든 데이터 항목에 값이 있어야하는 것은 아닙니다. 예를 들어 디스크 파일에서 데이터를 읽을 때 데이터가 디스크에서 들어온 후 이동할 장소가 있어야합니다. 이와 같은 데이터 버퍼는 프로그램 의 .bss 섹션에 정의되어 있습니다. 버퍼에 대해 약간의 바이트를 따로 설정하고 버퍼에 이름을 지정하지만 버퍼에 어떤 값이 있는지는 말하지 않습니다.

.data 섹션에 정의 된 데이터 항목과 .bss 섹션에 정의 된 데이터 항목 간에는 중요한 차이가 있습니다. .data 섹션의 데이터 항목은 실행 파일의 크기에 추가됩니다. .bss 섹션의 데이터 항목은 그렇지 않습니다. 16,000 바이트 (또는 그 이상, 때로는 훨씬 더)를 차지하는 버퍼는 .bss에서 정의 할 수 있으며 실행 파일 크기에 거의 아무것도 추가하지 않습니다 (설명에 대해 약 50 바이트).


9

글쎄, 우선, 당신의 예제에있는 변수들은 초기화되지 않은 것이 아닙니다. C는 초기화되지 않은 정적 변수가 0으로 초기화되도록 지정합니다.

따라서 .bss의 이유는 로더가 디스크에서 데이터를 복사하는 대신 0을 할당 할 수 있기 때문에 실행 파일이 작아 공간을 절약하고 프로그램을 더 빠르게로드 할 수 있기 때문입니다.

프로그램을 실행할 때 프로그램 로더는 .data 및 .bss를 메모리에로드합니다. 따라서 .data 또는 .bss에있는 개체에 쓰기는 메모리로만 이동하며 디스크의 바이너리로 어떤 지점에서도 플러시되지 않습니다.


5

시스템 V ABI 4.1 (1997) (일명 ELF 사양)도 답이 들어 있습니다 :

.bss이 섹션은 프로그램의 메모리 이미지에 기여하는 초기화되지 않은 데이터를 보유합니다. 정의에 따라 시스템은 프로그램이 실행되기 시작할 때 데이터를 0으로 초기화합니다. 섹션 유형으로 표시된대로 섹션은 파일 공간을 차지하지 않습니다 SHT_NOBITS.

섹션 이름은 말한다 .bss예약되어 있으며 특히 특수 효과가 없는 파일 공간을 차지하지 이상 때문에, 장점 .data.

단점은 물론 0OS가 메모리에 저장할 때 모든 바이트를 설정해야한다는 것입니다 . 이는 더 제한적이지만 일반적인 사용 사례이며 초기화되지 않은 변수에 대해 잘 작동합니다.

SHT_NOBITS섹션 유형 내용은 해당 긍정을 반복합니다 :

sh_size이 멤버는 섹션의 크기를 바이트 단위로 제공합니다. 섹션 유형이 SHT_NOBITS이면 섹션은 sh_size 파일에서 바이트를 차지 합니다. 유형 섹션의 SHT_NOBITS크기가 0이 아닐 수 있지만 파일에서 공간을 차지하지 않습니다.

C 표준 섹션에 대해 아무것도 말하지 않는다, 그러나 우리는 쉽게 변수가 리눅스에 저장되는 위치를 확인할 수 있습니다 objdumpreadelf및 초기화되지 않은 전역이 실제로에 저장됩니다 결론 .bss. 예를 들어이 답변을보십시오 : C에서 선언되고 초기화되지 않은 변수는 어떻게됩니까?


3

위키피디아 기사 .bss 는 용어가 1950 년대 중반 (yippee my birthday ;-)의 용어라는 점을 감안할 때 멋진 역사적 설명을 제공합니다.

예전에는 모든 비트가 소중했기 때문에 예약 된 빈 공간을 알리는 모든 방법이 유용했습니다. 이 ( .bss )는 멈춘 것입니다.

.data 섹션은 비어 있지 않은 공간을위한 것이며, 대신 (사용자의) 정의 된 값이 입력됩니다.

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