2016-06-21 2 views
7

여기 진 크기를 증가는 이야기입니다. Keil을 사용하기 전에 (자신의 툴체인이있는) Windows 용 GNU-toolchain (ARM 임베디드 프로세서 용 GNU Tools) 5.2.1)로 마이그레이션했습니다. 내가 처음 깨달은 것은; 바이너리 파일 크기가 크게 증가했습니다. 모든 컴파일러 최적화를 테스트했습니다 (링크 시간 최적화를 제외하고는 인라인 어셈블리에 오류가 발생하고 질문에는 포함되지 않지만 대답과 관련 될 수 있음). 그런 다음 사용 가능한 도구 (objdump, readelf, nm)를 사용하여 실행 파일을 검사하기 시작했습니다 (elf 파일은 bin이 아니며 gnu는 두 파일 모두를 생성합니다). 내가 크기 증가의 원인이 일부 기호를 발견, 중요한 사람은 'd_print_comp_inner', 'd_exprlist', 'd_template_args'. 그러나이 기능이 바이너리로 나타나게하는 원인이 무엇인지 모릅니다. (나는 최소한의 라이브러리를 사용했다 : nano newlib). 길고 짧게 나는 범인을 찾기 위해 하나씩 코드를 제거하기 시작했다. 마침내 추상적 인 메소드 선언이었습니다!선언 추상 클래스 (순수 가상 메서드) 실질적으로

정의 기능 45킬로바이트 및 I 언급 한 심볼을 추가

virtual Return_type function_name(...)=0; 

대신

virtual Return_type function_name(...); 

있다. 그리고 이것은 소스 코드에서 유일한 변화입니다. 기본 클래스의 빈 정의가 있습니다. 방법은 여전히 ​​가상과 추상 클래스하지 않고 자식 클래스

크기 출력에서 ​​재정의 :주의 추상 클래스와

text data  bss  dec  hex filename 
    15316  24 4764 20104 4e88 temc_discovery.elf 

크기 출력 : 여기

text data  bss  dec  hex filename 
    61484  128 4796 66408 10368 temc_discovery.elf 

기호와 그들의 크기가 메소드가 추상 메소드 인 경우 두 버전에서 모두 제거됩니다. (nm 도구가 사용된다. 안 전체 목록은 크기> = 0x60으로 가진 것들)

00002de4 t d_print_comp_inner 
00001a34 t d_exprlist 
00000ca4 t d_template_args 
00000678 t d_type 
00000574 t d_print_mod 
000003f8 t d_encoding 
000003e0 r cplus_demangle_operators 
000003c8 t d_expression_1 
000003a8 t d_name 
00000354 t d_demangle_callback.constprop.15 
000002e0 t d_print_mod_list 
00000294 r cplus_demangle_builtin_types 
00000268 t d_unqualified_name 
00000244 T _printf_i 
00000238 t d_print_function_type.isra.11 
000001fc T _svfprintf_r 
000001fc T _svfiprintf_r 
000001f4 t d_print_array_type.isra.10 
000001ce t d_print_cast.isra.12 
0000018c t d_substitution 
00000110 t d_operator_name 
0000010c T __sflush_r 
000000e8 T __swsetup_r 
000000e6 t d_cv_qualifiers 
000000e0 t d_print_subexpr 
000000e0 t d_expr_primary 
000000dc T _printf_common 
000000cc T __cxa_demangle 
000000c8 t d_source_name 
000000c4 r standard_subs 
000000c4 T __ssputs_r 
000000b0 T __swbuf_r 
000000ac T _malloc_r 
000000a8 T _fputs_r 
000000a4 T __smakebuf_r 
000000a0 T __gnu_cxx::__verbose_terminate_handler() 
00000096 t d_print_expr_op 
0000008c T _free_r 
0000008c t d_parmlist 
0000008a t d_growable_string_callback_adapter 
0000007c T __sfp 
00000072 t d_append_buffer 
00000068 T __sinit 
00000060 d impure_data 

나 (등 fputs의 printf, 플러시, malloc에, 등)에 익숙한 일부 이름은 심지어 소스에 언급되지 않은 암호.

이 문제의 원인을 어떤 생각으로 어떤 하나?

업데이트 : 이미 플래그 --noexception에 예외를 해제했다, 그래서 나는 그것에 비록 어떤을 부여하지 않았습니다. 그것이 밝혀 졌을 때, 이것은 여기에 언급하기에 너무 좋은 대답과 관련이 있습니다. 당신이 답변에 링크를 추적하는 경우, 모든 것을 설명 This is the most comprehensive website :

업데이트 2.

+0

컴파일 및 링크 명령을 제공하기 위해 더 좋을 수있다, 예를 들어, libc의 버전에서 변경 될 수 있습니다 비록 내가, 우리의 프로젝트가 무엇인가 '-g' 옵션은 디버그 심볼 등을위한 더 큰 바이너리를 생성 할 것이다. 그리고 여러분은 스트립 된 바이너리의 크기를 검사 할 수있다. – Mine

+0

슬픈 것처럼 모든 컴파일러 최적화를 시도했습니다. 동일한 결과 (40KB 증가). – ifyalciner

+2

해결책. 아마도 여기에 이미 나와 있습니다 : https://stackoverflow.com/questions/14689639/can-i-disable-exceptions-for-when-a-pure-virtual-function-is-called – deniss

답변

6

--noexception 또는 적절한 gnu-ism이 무엇이든 관계없이 코드를 컴파일하는지 여부에 관계없이 libC++에 내장 된 예외 처리가 예기치 않게 포함 되었기 때문에 거의 확실합니다.

예외는 '순수 가상 함수 호출'또는 그와 비슷한 것입니다 (얻을 수있는 상당히 모호한 런타임 오류이지만 기본 클래스 생성자에서 가상 함수를 호출하면 가능합니다).

대답은 이것, atexit() 및 사용자가 실제로 필요하지 않은 임의의 임의의 설명 선의 빈 구현을 제공하는 것입니다. 일단 그렇게하면, 링커는 다른 것들 (다른 것들에 끌리는, 다른 것들에 끌리는 등)에서 끌리지 않습니다.

void __cxa_pure_virtual(void) 
{ 
    BKPT(); 
} 

상황이 ++

+0

답변 해 주셔서 감사합니다. 그것은 효과가 있었다. – ifyalciner

5

내가 이해하는 한 기본 클래스 에서 가상 함수를 만들 때 순수을 만들면 순수 가상 전화를 만들 수있는 가능성이 생깁니다. 따라서 컴파일러는 순수 가상 호출 사실, 함수 및 클래스의 이름을 다르게 표시 한 메시지를 인쇄하는 코드를 생성하며 다른 코드 일 수 있습니다. 바이너리에 여러 함수가 추가되어 크기가 커집니다.

나는 당신의 순수 가상 함수에 빈 구현을 추가하는 것이 좋습니다 - 그것은 그 물건을에서 컴파일러를 방지 할 수있다.

+0

코드의 변경 만 '= 0'입니다. 그래서 '함수 정의되지 않은 오류'를 얻지 않기 위해서 이미 함수 정의가 비어 있습니다. – ifyalciner

+0

참조 http://stackoverflow.com/questions/99552/where-do-pure-virtual-function-call-crashes-come-from –

+0

@ifyalciner, 함수에 대해 = 0을 모두 가질 수 있으며 빈 구현입니다. 가상 소멸자. – user2807083

관련 문제