programing

gcc의 on-function-section 및 -f 데이터-section 옵션 쿼리

bestprogram 2023. 6. 11. 11:06

gcc의 on-function-section 및 -f 데이터-section 옵션 쿼리

아래는 기능 섹션 및 데이터 섹션 옵션에 대한 GCC 페이지에 나와 있습니다.

-ffunction-sections
-fdata-sections

대상이 임의 섹션을 지원하는 경우 각 함수 또는 데이터 항목을 출력 파일의 해당 섹션에 배치합니다.함수의 이름 또는 데이터 항목의 이름에 따라 출력 파일의 섹션 이름이 결정됩니다.링커가 최적화를 수행하여 명령 공간의 참조 위치를 개선할 수 있는 시스템에서 이 옵션을 사용합니다.ELF 개체 형식을 사용하는 대부분의 시스템과 Solaris 2를 실행하는 SPARC 프로세서에는 이러한 최적화 기능이 있는 링커가 있습니다. AIX는 향후 이러한 최적화 기능이 있을 수 있습니다.

이러한 옵션은 이러한 옵션을 사용함으로써 상당한 이점이 있을 때만 사용하십시오.이러한 옵션을 지정하면 어셈블리 및 링커가 더 큰 개체 및 실행 파일을 생성하고 속도가 느려집니다.이 옵션을 지정하면 모든 시스템에서 gprof를 사용할 수 없으며 이 옵션과 -g를 모두 지정하면 디버깅에 문제가 있을 수 있습니다.

이러한 옵션이 실행 파일 크기를 줄이는 데 도움이 될 것이라는 생각이 들었습니다.이 페이지에 더 큰 실행 파일을 만들 것이라고 표시되는 이유는 무엇입니까?내가 뭘 빼놓았나요?

흥롭게도를 사용하는 것은 하기용사입니다.-fdata-sections사용자의 함수 풀을 문자 그대로 만들 수 있으므로 함수 자체를 더 크게 만들 수 있습니다.저는 특히 ARM에서 이것을 발견했지만, 다른 곳에서는 사실일 가능성이 높습니다.제가 테스트한 바이너리는 0.25% 성장하는데 그쳤지만, 성장했습니다.변경된 기능의 분해를 보면 그 이유를 알 수 있었습니다.

개체 파일의 모든 BSS(또는 DATA) 항목이 단일 섹션에 할당된 경우 컴파일러는 해당 섹션의 주소를 함수 리터럴 풀에 저장하고 함수의 해당 주소에서 알려진 오프셋으로 로드를 생성하여 데이터에 액세스할 수 있습니다. 하만활하면화성지면을 하면.-fdata-sections각 BSS(또는 DATA) 데이터 조각을 자체 섹션에 배치하고, 이러한 섹션 중 어떤 섹션이 나중에 가비지 수집되는지 또는 링커가 이 모든 섹션을 최종 실행 이미지에 배치할 순서를 모르기 때문에 단일 주소의 오프셋을 사용하여 더 이상 데이터를 로드할 수 없습니다.따라서 사용된 데이터별로 리터럴 풀의 항목을 할당해야 합니다. 링커가 최종 이미지에 무엇이 들어가고 어디로 가는지 파악한 후에는 데이터의 실제 주소로 리터럴 풀 항목을 수정할 수 있습니다.

는▁with▁so,네,지서.-Wl,--gc-sections실제 함수 텍스트가 더 크기 때문에 결과 이미지가 더 커질 수 있습니다.

아래에 최소한의 예를 추가했습니다.

아래 코드는 제가 말하는 행동을 확인하기에 충분합니다.실제 코드에서 의심스러운 글로벌 변수의 변동성 선언과 사용에 당황하지 마십시오.여기서 -f 데이터 섹션을 사용할 때 두 개의 데이터 섹션을 만들 수 있습니다.

static volatile int head;
static volatile int tail;

int queue_empty(void)
{
    return head == tail;
}

이 테스트에 사용되는 GCC 버전은 다음과 같습니다.

gcc version 6.1.1 20160526 (Arch Repository)

첫째, -f 데이터 섹션이 없으면 다음과 같은 정보를 얻을 수 있습니다.

> arm-none-eabi-gcc -march=armv6-m \
                    -mcpu=cortex-m0 \
                    -mthumb \
                    -Os \
                    -c \
                    -o test.o \
                    test.c

> arm-none-eabi-objdump -dr test.o

00000000 <queue_empty>:
 0: 4b03     ldr   r3, [pc, #12]   ; (10 <queue_empty+0x10>)
 2: 6818     ldr   r0, [r3, #0]
 4: 685b     ldr   r3, [r3, #4]
 6: 1ac0     subs  r0, r0, r3
 8: 4243     negs  r3, r0
 a: 4158     adcs  r0, r3
 c: 4770     bx    lr
 e: 46c0     nop                   ; (mov r8, r8)
10: 00000000 .word 0x00000000
             10: R_ARM_ABS32 .bss

> arm-none-eabi-nm -S test.o

00000000 00000004 b head
00000000 00000014 T queue_empty
00000004 00000004 b tail

arm-none-eabi-nm이고 queue_empty는 20바이트(1416진수)입니다.arm-none-eabi-objdump출력은 함수의 끝에 단일 재배치 단어가 있음을 나타냅니다. 이는 BSS 섹션(초기화되지 않은 데이터 섹션)의 주소입니다.함수의 첫 번째 명령은 해당 값(BSS의 주소)을 r3에 로드합니다.다음 두 명령은 r3에 상대적으로 로드되어 각각 0 및 4바이트씩 오프셋됩니다.이 두 하중은 머리와 꼬리 값의 하중입니다.다음 출력의 첫 번째 열에서 오프셋을 확인할 수 있습니다.arm-none-eabi-nm.nop기능의 끝에 있는 것은 리터럴 풀의 주소를 워드 정렬하는 것입니다.

다음으로 -fdata-sections가 추가되면 어떻게 되는지 살펴보겠습니다.

arm-none-eabi-gcc -march=armv6-m \
                  -mcpu=cortex-m0 \
                  -mthumb \
                  -Os \
                  -fdata-sections \
                  -c \
                  -o test.o \
                  test.c

arm-none-eabi-objdump -dr test.o

00000000 <queue_empty>:
 0: 4b03     ldr   r3, [pc, #12]    ; (10 <queue_empty+0x10>)
 2: 6818     ldr   r0, [r3, #0]
 4: 4b03     ldr   r3, [pc, #12]    ; (14 <queue_empty+0x14>)
 6: 681b     ldr   r3, [r3, #0]
 8: 1ac0     subs  r0, r0, r3
 a: 4243     negs  r3, r0
 c: 4158     adcs  r0, r3
 e: 4770     bx    lr
    ...
             10: R_ARM_ABS32 .bss.head
             14: R_ARM_ABS32 .bss.tail

arm-none-eabi-nm -S test.o

00000000 00000004 b head
00000000 00000018 T queue_empty
00000000 00000004 b tail

즉시 queue_empty의 길이가 4바이트 증가하여 24바이트(1816진수)가 되었으며 queue_empty의 리터럴 풀에서 수행해야 할 두 개의 재배치가 있음을 알 수 있습니다.이러한 재배치는 각 글로벌 변수에 대해 하나씩 생성된 두 BSS 섹션의 주소에 해당합니다.컴파일러는 링커가 두 섹션을 삽입하게 될 상대적 위치를 알 수 없기 때문에 여기에 두 개의 주소가 있어야 합니다.queue_empty의 시작 부분에 있는 명령어를 보면 추가 로드가 있음을 알 수 있습니다. 컴파일러는 섹션의 주소와 해당 섹션의 변수 값을 얻기 위해 별도의 로드 쌍을 생성해야 합니다.이 버전의 queue_empty에서 추가 명령어를 사용하면 함수의 본문이 길어지는 것이 아니라 이전에 사용하지 않았던 자리를 차지할 뿐이지만 일반적으로는 그렇지 않습니다.

이러한 컴파일러 옵션을 사용할 때 링커 옵션을 추가할 수 있습니다.-Wl,--gc-sections사용되지 않는 모든 코드를 제거합니다.

사용할 수 있습니다.-ffunction-sections그리고.-fdata-sections각 함수와 전역 데이터 변수가 별도의 섹션에 배치되므로 정적 라이브러리의 크기가 증가합니다.

그런 다음 사용합니다.-Wl,--gc-sections이 정적 라이브러리와 연결된 프로그램에서 사용되지 않는 섹션을 제거합니다.

따라서 이러한 플래그가 없는 경우보다 최종 이진수가 더 작아집니다.

하지만 조심하세요, 왜냐하면-Wl,--gc-sections물건을 부술 수 있습니다.

추가 단계를 추가하고 더 나은 결과를 얻을 수 있습니다..a보관:

  1. 는 첫, gcc와 g++와 함께 됩니다.-ffunction-sections -fdata-sections
  2. 그 다음에.o는 물이안들니다어에 ..a으로 합니다.ar rcs file.a *.o
  3. 마지막으로, 링커는 다음과 같이 호출됩니다.-Wl,-gc-sections,-u,main 션들
  4. 모두를 위해, 최적화는 다음과 같이 설정됩니다.-Os.

얼마 전에 시도해봤는데 결과를 보니 정렬이 다른 물체의 순서에 따라 크기가 증가한 것 같습니다.일반적으로 링커는 개체를 정렬하여 두 개체 사이의 패딩을 작게 유지하지만 개별 섹션 간이 아니라 섹션 내에서만 작동하는 것처럼 보입니다.따라서 각 함수에 대해 데이터 섹션 사이에 추가 패딩이 발생하여 전체 공간이 증가하는 경우가 많습니다.

-Wl,-gc-sections가 있는 정적 lib의 경우, 사용되지 않는 섹션을 제거하면 작은 증가를 보충할 가능성이 높습니다.

언급URL : https://stackoverflow.com/questions/4274804/query-on-ffunction-section-fdata-sections-options-of-gcc