2016-06-21 18 views
7

Đây là câu chuyện: Tôi đang phát triển phần mềm C++ cho bộ xử lý ARM Cortex-M0 trong Linux với AC6 Toolpack. Trước khi tôi sử dụng Keil (trong các cửa sổ) (người có chuỗi công cụ riêng của họ) và tôi đã chuyển sang GNU-toolchain ((Công cụ GNU dành cho Bộ xử lý nhúng ARM) 5.2.1). Điều đầu tiên tôi đã nhận ra là; kích thước tệp nhị phân tăng đáng kể. Tôi đã thử nghiệm mọi tối ưu hóa trình biên dịch (ngoại trừ tối ưu hóa thời gian liên kết, nó đưa ra một lỗi trong lắp ráp nội tuyến, không phải là một phần của câu hỏi nhưng có thể liên quan đến câu trả lời). Sau đó bắt đầu kiểm tra các tập tin thực thi (tập tin elf không bin, gnu sản xuất cả hai) với bất kỳ công cụ có sẵn: objdump, readelf, nm. Tôi đã tìm thấy một số biểu tượng gây ra tăng kích thước, các biểu tượng quan trọng là: 'd_print_comp_inner', 'd_exprlist', 'd_template_args'. Nhưng không có ý tưởng những gì đang gây ra các chức năng này xuất hiện trong nhị phân. (tôi đã sử dụng các thư viện tối thiểu: nano newlib). Truyện ngắn tôi bắt đầu loại bỏ từng mã một để tìm ra thủ phạm. Cuối cùng nó đã được khai báo phương pháp trừu tượng!Khai báo lớp trừu tượng (phương pháp ảo thuần túy) tăng kích thước nhị phân đáng kể

Xác định chức năng như

virtual Return_type function_name(...)=0; 

thay vì

virtual Return_type function_name(...); 

thêm 45 KB và những biểu tượng tôi đã đề cập. Và đây là thay đổi duy nhất trong mã nguồn. Định nghĩa rỗng trong lớp cơ sở là hiện tại. Lưu ý rằng: Phương pháp vẫn còn ảo và ghi đè trong các lớp con

Kích đầu ra mà không Abstract Class:

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

Kích đầu ra với Abstract Class:

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

Ở đây, các biểu tượng và kích thước của họ mà hiển thị khi phương thức trừu tượng, loại bỏ các phương thức hiển thị trong cả hai phiên bản. (nm công cụ được sử dụng. Không danh sách đầy đủ, là những người có kích thước> = 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 

Một số cái tên quen thuộc đối với tôi (như printf, tuôn ra, malloc, fputs vv) được thậm chí không được đề cập trong nguồn mã.

Bất kỳ ai có bất kỳ ý tưởng nào đang gây ra hành vi này?

Cập nhật: tôi đã được vô hiệu hóa ngoại lệ với cờ --noexception, vì vậy tôi đã không đưa ra bất kỳ mặc dù với nó. Khi nó quay ra, nó có liên quan đến câu trả lời rất tốt để đề cập đến điều này ở đây.

Cập nhật 2: This is the most comprehensive website giải thích tất cả, nếu bạn theo dõi liên kết trong câu trả lời.

+0

Nó có thể là tốt hơn để cung cấp các biên dịch và liên kết lệnh, ví dụ Tùy chọn '-g' sẽ tạo ra nhị phân lớn hơn cho các biểu tượng gỡ lỗi, v.v. Và bạn có thể kiểm tra kích thước nhị phân bị tước. – Mine

+0

Như tôi buồn, tôi đã thử tất cả các tối ưu hóa trình biên dịch. Cùng một kết quả (với mức tăng cao hơn 40 KB). – ifyalciner

+2

Giải pháp. có lẽ, đã được đưa ra ở đây: https://stackoverflow.com/questions/14689639/can-i-disable-exceptions-for-when-a-pure-virtual-function-is-called – deniss

Trả lời

6

Nó gần như chắc chắn vì việc xử lý ngoại lệ không mong muốn, mà libC++ đã tích hợp vào nó, bất kể bạn có biên dịch mã của mình với --noexception hay bất kỳ gnu-ism nào.

Ngoại lệ trong câu hỏi có thể là 'gọi hàm ảo thuần túy' hoặc một cái gì đó tương tự (một lỗi thời gian chạy khá mơ hồ để có được, nhưng có thể nếu bạn gọi hàm ảo trong hàm tạo lớp cơ sở).

Câu trả lời là cung cấp việc triển khai trống rỗng của riêng bạn, atexit() và bất kỳ chú thích ngẫu nhiên nào mà bạn không thực sự cần. Một khi bạn làm điều đó, trình liên kết sẽ không kéo trong các công cụ khác (mà kéo trong các công cụ khác, mà kéo trong công cụ khác, vv).

void __cxa_pure_virtual(void) 
{ 
    BKPT(); 
} 

phải là những gì tôi có trong dự án của chúng tôi, mặc dù điều có thể đã thay đổi trong phiên bản của libC++

+0

Cảm ơn câu trả lời. Nó đã làm việc. – ifyalciner

5

Theo tôi hiểu, khi bạn thực hiện chức năng ảo của mình trong lớp cơ sở tinh khiết bạn tạo ra tiềm năng thực hiện cuộc gọi ảo thuần túy. Vì vậy, trình biên dịch tạo ra mã nơi nó in thông báo về thực tế cuộc gọi ảo tinh khiết, các tên bị hỏng cho hàm và lớp và có thể là một cái gì đó khác. Nó cho biết thêm nhiều chức năng cho nhị phân của bạn cho điều đó, vì vậy kích thước tăng lên.

Tôi đề xuất thêm triển khai trống vào chức năng ảo thuần túy của bạn - có thể ngăn trình biên dịch thực hiện công việc đó.

+0

Chỉ thay đổi mã là '= 0'. Vì vậy, để không nhận được 'chức năng không được xác định lỗi' Tôi đã có định nghĩa trống của chức năng. – ifyalciner

+0

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

+0

@ifyalciner, bạn có thể có cả hai = 0 cho hàm và triển khai trống, ví dụ: destructor ảo. – user2807083

Các vấn đề liên quan