ARM 링커 최적화 기능 소개

공통 그룹 제거

링커는 섹션 그룹의 여러 복사본을 감지하고 나머지는 삭제할 수 있습니다.

® Embedded용 Arm 컴파일러는 연결을 위한 완전한 객체를 생성합니다. 그러므로:

  • 인라인 함수가 C 및 C++ 소스 코드에 있는 경우 각 개체에는 개체에 필요한 인라인 함수의 라인 외부 복사본이 포함됩니다.
  • C++ 소스 코드에서 템플릿을 사용하는 경우 각 개체에는 개체에 필요한 템플릿 함수가 포함됩니다.

이러한 함수가 공통 헤더 파일에 선언되면 이후에 서로 연결되는 별도의 개체에서 여러 번 정의될 수 있습니다. 중복을 제거하기 위해 컴파일러는 이러한 함수를 공통 섹션 그룹의 별도 인스턴스로 컴파일합니다.

공개 섹션 그룹의 개별 인스턴스는 동일하지 않을 수 있습니다. 예를 들어 일부 복사본은 다르지만 호환 가능한 빌드 옵션, 다른 최적화 또는 디버깅 옵션으로 빌드된 라이브러리에 있을 수 있습니다.

복사본이 동일하지 않은 경우 则 armlink 각 공통 섹션 그룹의 사용 가능한 가장 적합한 변형이 입력 개체의 속성에 따라 유지됩니다. Armlink 나머지는 폐기하십시오.

복사본이 동일한 경우 则 armlink 찾은 첫 번째 부분 그룹이 유지됩니다.

다음 링커 옵션을 사용하여 이 최적화를 제어할 수 있습니다.

  • 가장 큰 공통 데이터(COMDAT) 그룹을 사용하려면 -옵션을 사용하십시오 -bestdebug (아마도 최상의 디버깅 보기 제공).
  • 가장 작은 COMDAT 그룹을 사용하려면 - -no_bestdebug 옵션을 사용하십시오(아마도 가장 작은 코드 크기 제공). 이것이 기본 설정입니다.

    -를 사용하여 g COMDAT 그룹 A가 포함된 모든 파일을 컴파일하면 -no_bestdebug-를 사용하더라도 이미지가 변경됩니다.

 사용하지 않는 부품 제거

사용되지 않는 부분을 제거하는 것은 링커가 이미지 크기에 대해 수행하는 가장 중요한 최적화입니다.

사용하지 않는 부품 제거:

  • 최종 이미지에서 액세스할 수 없는 코드와 데이터를 제거합니다.
  • 모든 부분이 삭제될 수 있는 상황에서는 표시되지 않습니다.

이 최적화를 제어하려면  armlink -- remove, -- no_remove, --first, - -last 및 - 옵션을 사용하십시오 -keep.

사용하지 않은 부분을 제거하려면 진입점이 필요합니다. 따라서 이미지에 진입점이 지정되지 않은 경우 -   진입점 지정 armlink 옵션을 사용하세요.-entry

옵션 사용  armlink - -info unused 제거할 사용되지 않은 섹션 목록을 생성하도록 링커에 지시합니다.

알아채다

armlink 错误:L6218E:未定义的符号 <symbol> 사용되지 않는 부분을 제거하더라도 이 기호가 제거되었음을  보고합니다 . 이 동작은 GNU 링커와 다릅니다  ld  .

다음과 같은 경우 입력 부분이 최종 이미지에 유지됩니다.

  • 여기에는 진입점 또는 외부에서 액세스 가능한 기호가 포함되어 있습니다. 예를 들어 Arm® v8-M 보안 확장의 보안 코드에 입력 기능이 있습니다.
  • SHT_INIT_ARRAY, SHT_FINI_ARRAY또는 SHT_PREINIT_ARRAY일부 입니다 .
  • first --or 옵션  이나 스캐터 로딩에 해당 하는 옵션으로 지정되는 첫 번째 또는 마지막 입력 부분으로 지정됩니다 --last .
  • --keep 옵션에 분리 불가능으로 표시되어 있습니다  .
  • 이미지에 포함된 입력 부분에 대한 약하지 않은 참조에 의해 직접 또는 간접적으로 참조됩니다.
  • 해당 이름은 입력 섹션 기호에서 참조하는 이름과 일치하며 기호는 이미지에 유지된 섹션에서 참조됩니다.

알아채다

컴파일러는 일반적으로 함수와 데이터를 함께 수집하고 각 범주에 대한 섹션을 내보냅니다. 링커는 완전히 사용되지 않는 부분만 제거할 수 있습니다.

__attribute__(used)) 속성을 사용하여 소스 코드에서 함수나 변수를 표시 할 수 있습니다  . 이 속성을 사용하면  각 함수나 변수에 대해 <num>  armclang 기호가  생성됩니다. 여기서  는 각 기호를 구별하는 데 사용되는 카운터입니다. 사용하지 않는 섹션을 제거해도 포함된 섹션은 삭제되지 않습니다   .__tagsym$$used.<num>__tagsym$$used.<num>

armclang - 옵션을 사용하여 ffunction-sections 소스 파일의 각 함수에 대해 ELF 섹션을 생성하도록 컴파일러에 지시할 수도 있습니다  . 

RW 데이터 압축을 사용하여 최적화

RW 데이터 영역에는 많은 수의 반복 값(예: 0)이 포함되어 있어 압축에 적합한 경우가 많습니다.

기본적으로 ROM 크기를 최소화하기 위해 RW 데이터 압축이 활성화됩니다.

링커는 데이터를 압축합니다. 그런 다음 이 데이터는 런타임 시 대상에서 압축이 풀립니다.

Arm 라이브러리에는 다양한 압축 해제 알고리즘이 포함되어 있으며 링커는 이미지가 실행될 때 데이터 영역의 압축을 풀기 위해 이미지에 추가할 최상의 알고리즘을 선택합니다. 링커에서 선택한 알고리즘을 재정의할 수 있습니다.

링커가 압축기를 선택하는 방법

Armlink 가장 작은 이미지를 생성하는 데 가장 적합한 압축 알고리즘을 선택하기 전에 데이터 일부의 내용에 대한 정보를 수집하십시오.

압축이 적절한 경우 armlink 이미지의 압축 가능한 모든 데이터 부분에 하나의 데이터 압축기만 사용할 수 있습니다. 최상의 전체 크기를 생성하기 위해 이러한 부품에 대해 다양한 압축 알고리즘을 시도할 수 있습니다. 다음과 같은 경우 압축이 자동으로 적용됩니다.

Compressed data size + Size of decompressor < Uncompressed data size

압축기를 선택하면 armlink 이미지의 코드 영역에 압축해제기가 추가됩니다. 최종 이미지에 압축된 데이터가 포함되어 있지 않으면 압축 해제기가 추가되지 않습니다.

링커에서 사용하는 압축 알고리즘을 재정의하는 데 사용할 수 있는 옵션

링커에는 압축을 비활성화하거나 사용할 압축 알고리즘을 지정하는 옵션이 있습니다.

링커에서 사용하는 압축 알고리즘은 다음 방법 중 하나로 재정의할 수 있습니다.

  • -datacompressor off 압축을 끄려면 - 옵션을 사용하십시오 .
  • 압축 알고리즘을 지정합니다.

압축 알고리즘을 지정하려면 링커 명령줄에 원하는 압축기 번호를 사용합니다. 예:

armlink --datacompressor 2 ...

명령줄 옵션 사용 - -datacompressor list 링커에서 사용할 수 있는 압축 알고리즘 목록을 가져옵니다.

armlink --datacompressor list
...
Num     Compression algorithm
========================================================
0       Run-length encoding
1       Run-length encoding, with LZ77 on small-repeats
2       Complex LZ77 compression

압축 알고리즘을 선택할 때 다음 사항에 유의하십시오.

  • 압축기 0은 0바이트가 많지만 0이 아닌 바이트가 적은 데이터에서 잘 작동합니다.
  • 압축기 1은 0이 아닌 바이트 중복이 있는 데이터를 처리할 때 잘 작동합니다.
  • 압축기 2는 중복 값이 ​​포함된 데이터를 처리할 때 잘 작동합니다.

링커는 데이터가 대부분 0바이트(>75%)를 포함하는 압축기 0 또는 1을 선호합니다. 압축기 2를 선택하면 데이터에 0바이트가 거의 포함되지 않습니다(<10%). 이미지가 A32 코드로만 구성된 경우 A32 압축 해제기가 자동으로 사용됩니다. 이미지에 T32 코드가 포함되어 있으면 T32 압축 해제기가 사용됩니다. 명확한 선호 사항이 없는 경우 모든 압축기는 최상의 전체 크기를 생성하기 위해 테스트됩니다.

 

RW 데이터 압축 사용 시 주의 사항

RW 데이터 압축을 사용할 때 몇 가지 고려 사항이 있습니다.

RW 데이터 압축을 사용하는 경우:

  • 링커 옵션 사용 - -map 코드 영역에 압축이 적용되는 위치를 확인하세요.
  • 로드 주소를 사용하여 압축된 영역에서 링커 정의 기호에 대한 참조가 있는 경우 링커는 RW 압축을 끕니다.
  • 온칩 캐시가 포함된 Arm® 프로세서를 사용하는 경우 압축 해제 후 캐시를 활성화하여 코드 일관성 문제를 방지하세요.

압축된 데이터 세그먼트는 Arm 라이브러리의 코드를 사용하여 실행되는 경우 런타임 시 자동으로 압축이 풀립니다 __main. 이 코드는 루트 영역에 배치되어야 합니다. InRoot$$Sections 이는 스캐터 파일을 사용하는  것이 가장 좋습니다.

스캐터 파일을 사용하는 경우  NOCOMPRESS 속성을 추가하여 로드 또는 실행 영역이 압축되지 않도록 지정할 수 있습니다.

링커와 인라인으로 함수

링커 인라인 기능은 지정한 옵션과 입력 파일의 내용에 따라 달라집니다.

링커는 해당 함수에 대한 분기 명령 대신 작은 함수를 인라인할 수 있습니다. 링커가 이를 수행할 수 있으려면 함수(반환 명령 없이)가 분기 명령의 4바이트 내에 맞아야 합니다.

-- inline 및 -- -no_inline 명령줄 옵션을 사용하여 분기 인라인을 제어합니다. 그러나 -no_inline 사용자가 제공한 객체의 인라인만 끕니다. 기본적으로 링커는 여전히 Arm 표준 라이브러리의 함수를 인라인합니다.

분기 인라인 최적화가 활성화된 경우 링커는 이미지의 모든 함수 호출을 검색하고 필요에 따라 인라인합니다. 링커는 인라인에 적합한 함수를 찾으면 함수 호출을 호출되는 함수의 명령으로 바꿉니다.

링커는 사용되지 않는 섹션을 제거하기 전에 분기 인라인 최적화를 적용하므로 더 이상 호출되지 않는 인라인 섹션도 제거할 수 있습니다.

알아채다

  • Arm®v7-A의 경우 링커는 32비트로 인코딩된 Thumb® 명령어 대신 2개의 16비트로 인코딩된 Thumb 명령어를 인라인할 수 있습니다  BL .
  • Armv8-A 및 Armv8-M의 경우 링커는 32비트 T32 명령어 대신 2개의 16비트 T32 명령어를 인라인할 수 있습니다  BL .

-info=inline 모든 인라인 함수를 나열하려면 - 명령줄 옵션을 사용하십시오 .

NOP에 대한 분기 최적화 정보

링커가 분기를 대체할 수 있지만  NOP경우에 따라 이러한 일이 발생하지 않도록 방지할 수 있습니다.

NOP 기본적으로 링커는 모든 분기를 해당 명령어가 포함된 다음 명령어 로 확인되는 재배치로 바꿉니다  . 링커가 마무리 호출 섹션을 다시 정렬하는 경우에도 이 최적화를 적용할 수 있습니다.

그러나 어떤 경우에는 유효성 검사나 파이프라인 새로 고침을 수행할 때와 같이 이 옵션을 비활성화할 수 있습니다.

이 최적화를 제어하려면 - -branchnop 및  --no_branchnop 명령줄 옵션을 사용하십시오.

테일 콜 섹션의 링커 재정렬

어떤 경우에는 링커가 마무리 호출 섹션을 다시 정렬하도록 할 수도 있습니다.

tail call 섹션은 섹션 끝에 분기 명령이 포함된 섹션입니다. 분기 명령어에 다른 섹션에서 시작하는 함수를 대상으로 하는 재배치가 있는 경우 링커는 호출된 섹션 앞에 마무리 호출 섹션을 배치할 수 있습니다. 그런 다음 링커는 마무리 호출 섹션 끝에 있는 분기 명령을  NOP 명령으로 최적화할 수 있습니다.

이 동작을 활용하려면 명령줄 옵션을 사용하여 -tailreorder 대상 앞으로 마무리 호출 섹션을 이동합니다.

- -info=tailreorder 명령줄 옵션을 사용하면 링커에서 수행한 마무리 호출 최적화에 대한 정보를 표시할 수 있습니다.

테일 콜 부분 재정렬에 대한 제한 사항

테일 콜 섹션의 재정렬에는 몇 가지 제한 사항이 있습니다.

링커:

  • 각 tail call 대상에 대해 하나의 tail call 부분만 이동할 수 있습니다. 단일 섹션에 여러 개의 tail call이 있는 경우 동일한 섹션 이름을 가진 tail call 섹션이 대상 앞으로 이동됩니다. 일치하는 이름을 가진 마무리 호출 섹션에서 섹션 이름을 찾을 수 없는 경우 링커는 발견된 첫 번째 섹션을 이동합니다.
  • 마무리 호출 섹션은 실행 영역 밖으로 이동할 수 없습니다.
  • 꼬리는 인라인 베니어 앞에서 움직이지 않습니다.

동일한 상수 병합

링커는 AArch32 상태를 대상으로 하는 개체에서 동일한 상수를 병합하려고 시도할 수 있습니다. 객체는 Embedded 6용 Arm® 컴파일러를 사용하여 생성되어야 합니다. 옵션을 사용하여 컴파일하면  armclang -ffunction-sections 병합이 더 효율적입니다 . 이 옵션이 기본값입니다.

이 작업 정보

다음 절차는 병합 기능을 보여주는 예입니다.

알아채다

스캐터 파일을 사용하는 경우  OVERLAY 또는  속성으로 표시된 모든 영역은  옵션 동작에 PROTECTED 영향을 미칩니다  .armlink --merge_litpools

프로그램

  1. litpool.c다음 코드를 포함하는 C 소스 파일을 만듭니다  .
    int f1() {
        return 0xdeadbeef;
    }
    int f2() {
        return 0xdeadbeef;
    }
  2. 컴파일된 소스 코드를 사용하여  -S 어셈블리 파일을 만듭니다.
    armclang -c -S -target arm-arm-none-eabi -mcpu=cortex-m0 -ffunction-sections \
        litpool.c -o litpool.s

    알아채다

    - ffunction-sections 기본값입니다.

    0xdeadbeef명령어를 사용하여 생성하기 어려운 상수이므로 텍스트 풀이 생성됩니다. 예를 들면 다음과 같습니다 .

    ...
    f1:
        .fnstart
    @ BB#0:
        ldr    r0, __arm_cp.0_0
        bx     lr
        .p2align    2
    @ BB#1:
    __arm_cp.0_0:
        .long    3735928559              @ 0xdeadbeef
    ...
        .fnend
    
    ...
        .code    16                      @ @f2
        .thumb_func
    f2:
        .fnstart
    @ BB#0:
        ldr    r0, __arm_cp.1_0
        bx     lr
        .p2align    2
    @ BB#1:
    __arm_cp.1_0:
        .long    3735928559              @ 0xdeadbeef
    ...
        .fnend
    ...

    알아채다

    각 함수에는 상수의 복사본이 있습니다.  armclang 이러한 상수는 두 함수 간에 공유될 수 없기 때문입니다.
  3. 소스 코드를 컴파일하여 객체를 생성합니다.
    armclang -c -target arm-arm-none-eabi -mcpu=cortex-m0 litpool.c -o litpool.o
  4. 옵션을 사용하여  --merge_litpools 개체 파일을 연결합니다 .
    armlink --cpu=Cortex-M0 --merge_litpools litpool.o -o litpool.axf

    알아채다

    - -merge_litpools 기본값입니다.
  5. fromelf 이미지 구조를 보려면 다음을 실행하세요  .
    fromelf -c -d -s -t -v -z litpool.axf

    다음 예에서는 결합된 결과를 보여줍니다.

    ...
        f1
            0x00008000:    4801        .H      LDR      r0,[pc,#4] ; [0x8008] = 0xdeadbeef
            0x00008002:    4770        pG      BX       lr
        f2
            0x00008004:    4800        .H      LDR      r0,[pc,#0] ; [0x8008] = 0xdeadbeef
            0x00008006:    4770        pG      BX       lr
        $d.4
        __arm_cp.1_0
            0x00008008:    deadbeef    ....    DCD    3735928559
    ...

추천

출처blog.csdn.net/Miao8miao/article/details/135428505