2009-11-19 27 views
12

Đây là một mã từ trang man Linux:Các ký hiệu văn bản, edata và kết thúc được xác định ở đâu?

#include <stdio.h> 
#include <stdlib.h> 

extern char etext, edata, end; 

int main() { 
    printf("First address past:\n"); 
    printf(" program text (etext)  %10p\n", &etext); 
    printf(" initialized data (edata) %10p\n", &edata); 
    printf(" uninitialized data (end) %10p\n", &end); 

    exit(EXIT_SUCCESS); 
} 

khi chạy, chương trình dưới đây tạo ra sản lượng như sau:

$ ./a.out 
First address past: 
    program text (etext)  0x8048568 
    initialized data (edata) 0x804a01c 
    uninitialized data (end) 0x804a024 

đâu etext, edataend được xác định? Làm thế nào những biểu tượng được gán giá trị? Là nó bằng linker hay cái gì khác?

+0

Trang người nào? –

+1

Kiểm tra 'man 3 end' –

Trả lời

3

Các ký hiệu đó tương ứng với sự khởi đầu của các phân đoạn chương trình khác nhau. Chúng được thiết lập bởi trình liên kết.

7

Lưu ý rằng trên Mac OS X, mã ở trên có thể không hoạt động! Thay vào đó bạn có thể có:

#include <stdio.h> 
#include <stdlib.h> 
#include <mach-o/getsect.h> 

int main(int argc, char *argv[]) 
{ 
    printf(" program text (etext)  %10p\n", (void*)get_etext()); 
    printf(" initialized data (edata) %10p\n", (void*)get_edata()); 
    printf(" uninitialized data (end) %10p\n", (void*)get_end()); 

    exit(EXIT_SUCCESS); 
} 
2

GCC gì

Mở rộng kgiannakakis hơn một chút.

Những biểu tượng được xác định bởi các từ khóa PROVIDE của kịch bản mối liên kết, ghi nhận tại https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE

Giá trị mặc định kịch bản được tạo ra khi bạn xây dựng binutils và nhúng vào ld thực thi: tập tin bên ngoài có thể được cài đặt trong phân phối của bạn như trong /usr/lib/ldscripts không được sử dụng theo mặc định.

Echo kịch bản mối liên kết sẽ được sử dụng:

ld -verbose | less 

Trong binutils 2,24 nó chứa:

.text   : 
{ 
    *(.text.unlikely .text.*_unlikely .text.unlikely.*) 
    *(.text.exit .text.exit.*) 
    *(.text.startup .text.startup.*) 
    *(.text.hot .text.hot.*) 
    *(.text .stub .text.* .gnu.linkonce.t.*) 
    /* .gnu.warning sections are handled specially by elf32.em. */ 
    *(.gnu.warning) 
} 
.fini   : 
{ 
    KEEP (*(SORT_NONE(.fini))) 
} 
PROVIDE (__etext = .); 
PROVIDE (_etext = .); 
PROVIDE (etext = .); 
.rodata   : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 
.rodata1  : { *(.rodata1) } 

Vì vậy, chúng tôi cũng phát hiện ra rằng:

  • __etext_etext cũng sẽ làm việc
  • etext không phải là sự kết thúc của phần .text, nhưng thay vì .fini, mà cũng chứa mã
  • etext không phải là ở phần cuối của phân khúc này, với .rodata sau nó, vì binutils bãi tất cả các phần readonly vào cùng một phân khúc

PROVIDE tạo các ký hiệu yếu: nếu bạn cũng xác định các ký hiệu đó trong mã C của mình, định nghĩa của bạn sẽ giành được và ẩn biểu tượng này.

Minimal Linux 32-bit dụ

Để thực sự hiểu những điều làm việc, tôi muốn tạo ví dụ tối thiểu!

main.S:

.section .text 
    /* Exit system call. */ 
    mov $1, %eax 
    /* Exit status. */ 
    mov sdata, %ebx 
    int $0x80 
.section .data 
    .byte 2 

link.ld:

SECTIONS 
{ 
    . = 0x400000; 
    .text : 
    { 
     *(.text) 
     sdata = .; 
     *(.data) 
    } 
} 

Biên dịch và chạy:

gas --32 -o main.o main.S 
ld -m elf_i386 -o main -T link.ld main.o 
./main 
echo $? 

Output:

2 

Giải thích: sdata trỏ đến byte đầu tiên của phần bắt đầu của phần .data sau.

Vì vậy, bằng cách kiểm soát byte đầu tiên của phần đó, chúng tôi kiểm soát trạng thái thoát!

This example on GitHub.

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