2012-07-10 27 views
7

Giả sử tôi có một chức năng như dưới đây:Làm thế nào để có được kích thước của một hàm C từ bên trong một chương trình C hoặc với lắp ráp nội tuyến?

# cat 003.c 

int foo(int a, int b) 
{ 
    return a+b; 
} 

Và biên dịch nó như thế này:

gcc -S 003.c 

Các nhận kết quả lắp ráp sau:

 .file "003.c" 
    .text 
.globl foo 
    .type foo, @function 
foo: 
.LFB2: 
    pushq %rbp 
.LCFI0: 
    movq %rsp, %rbp 
.LCFI1: 
    movl %edi, -4(%rbp) 
    movl %esi, -8(%rbp) 
    movl -8(%rbp), %edx 
    movl -4(%rbp), %eax 
    addl %edx, %eax 
    leave 
    ret 
.LFE2: 
    .size foo, .-foo /* size of the function foo, how to get it?*/ 

Dòng cuối cùng a bove làm được kích thước của hàm. Trình biên dịch lưu trữ kích thước ở đâu? Tôi có thể lấy kích thước của hàm theo một cách nào đó trong chương trình C gốc của tôi không bằng cách sử dụng C hoặc nội tuyến asm?

+0

Thật không may '__builtin_object_size' không hoạt động (ít nhất với gcc 4.7) –

Trả lời

13

Các thông tin về kích thước chức năng được lưu trữ trong ELF Các thuộc tính cho ký hiệu tương ứng (tên). Mã ví dụ C cách phân tích cú pháp theo chương trình này ở dưới cùng của manpage Solaris cho gelf_getsym(3ELF) (libelf không tồn tại trong Linux, * BSD và MacOS, bạn cần tìm trường st_size của cấu trúc GElf_Sym), nhưng bạn cũng có thể sử dụng objdump/elfdump (Solaris)/readelf (Linux) cho nhiệm vụ:

$ objdump -h -d --section=.text foo3.o 

foo3.o:  file format elf64-x86-64 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
    0 .text   00000012 0000000000000000 0000000000000000 00000040 2**2 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
[ ... ] 
Disassembly of section .text: 

0000000000000000 <foo>: 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 89 7d fc    mov %edi,0xfffffffffffffffc(%rbp) 
    7: 89 75 f8    mov %esi,0xfffffffffffffff8(%rbp) 
    a: 8b 45 f8    mov 0xfffffffffffffff8(%rbp),%eax 
    d: 03 45 fc    add 0xfffffffffffffffc(%rbp),%eax 
    10: c9      leaveq 
    11: c3      retq

này là dành cho một biên dịch được tối ưu hóa mã của bạn, trong khi phiên bản tối ưu hóa là:

$ objdump -h -d --section=.text foo3.o 

foo3.o:  file format elf64-x86-64 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
    0 .text   00000004 0000000000000000 0000000000000000 00000040 2**4 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
[ ... ] 
Disassembly of section .text: 

0000000000000000 <foo>: 
    0: 8d 04 37    lea (%rdi,%rsi,1),%eax 
    3: c3      retq

Note "Kích thước "thay đổi từ 0x12 thành 4? Đó là những gì xuất phát từ chỉ thị lắp ráp .size.

"Bí quyết" của việc cố gắng sử dụng lắp ráp nội tuyến để cung cấp cho bạn kích thước chức năng/vị trí mã không được tính toán cho mã trình tạo mã trình biên dịch (phần mở đầu chức năng/đoạn trích xuất, tạo mã nội tuyến, ...) đối với trình biên dịch sắp xếp lại trình biên dịch nội tuyến (gcc là khét tiếng để làm như vậy), do đó nó thường không phải là một ý tưởng tuyệt vời để tin tưởng điều này. Cuối cùng, nó phụ thuộc vào những gì chính xác bạn đang cố gắng để làm ...

Edit: Một vài tài liệu tham khảo hơn, bên ngoài cũng như trên stackoverflow:

  1. Từ danh sách gửi thư gcc, thread on sizeof(function)
  2. what does sizeof (function name) return?
  3. Find size of a function in C
  4. LibELF by example dự án SourceForge (đây là tài liệu hướng dẫn/hướng dẫn)
+0

Tôi không hiểu: đầu ra objdump bạn trích dẫn cho thấy kích thước của phần văn bản, chứ không phải các chức năng riêng lẻ. 'readelf -s' tuy nhiên hiển thị thuộc tính' st_size' của các ký hiệu mà bạn đề cập đến. –

1

Tại sao không lấy sự khác biệt của con trỏ của hàm và địa chỉ hiện tại ở cuối hàm? Đã xem qua câu hỏi này để khôi phục lại địa chỉ IP hiện tại: Get address of current instruction for x86, có thể là mã này, stolen form one of the reply:

unsigned long get_PC() 
{ 
    unsigned long current_instruction; 

    __asm__ __volatile__ 
    (
     "movq 8(%rbp), %rax\n\t" 
     : "=a" (current_instruction) 
    ); 

    return current_instruction; 
} 

sẽ làm các trick,

+2

Điều đó sẽ rất mong manh, hãy để một mình di động. –

+0

không đồng ý về sự mong manh trong ý nghĩa của ý tưởng, có thể là cách bạn sử dụng để phục hồi địa chỉ, AFAIK gcc nên có một số cách nhúng để có được điều này, nhưng tôi không nhớ tên. –

+0

Nếu bạn thay đổi tùy chọn tối ưu hóa hoặc một số mã xung quanh, bạn có thể nhận được kết quả rất khác với thực tế. –