2010-11-08 245 views
4
int i; 
int main() { 
    return i;  
} 

編譯-staticreadelf -l顯示程序頭從精靈:ELF文件TLS和LOAD程序段

Elf file type is EXEC (Executable file) 
Entry point 0xxxxx30 
There are 6 program headers, starting at offset 52 

Program Headers: 
    Type   Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 
    LOAD   0x000000 0x08048000 0x08048000 0x79868 0x79868 R E 0x1000 
> LOAD   0x079f94 0x080c2f94 0x080c2f94 0x0078c 0x02254 RW 0x1000 << 
    NOTE   0x0000f4 0x080480f4 0x080480f4 0x00020 0x00020 R 0x4 
> TLS   0x079f94 0x080c2f94 0x080c2f94 0x00010 0x0002c R 0x4  << 
    GNU_STACK  0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 
    PAX_FLAGS  0x000000 0x00000000 0x00000000 0x00000 0x00000  0x4 

Section to Segment mapping: 
    Segment Sections... 
    00  .note.ABI-tag .init .text __libc_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit .eh_frame .gcc_except_table 
    01  .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs 
    02  .note.ABI-tag 
    03  .tdata .tbss 

有人可以解釋,爲什麼在第2和第4個節目標題不相交(它們具有相同的開始偏移0x079f94和VirtAddr 0x080c2f94)。

此外,段部分.tdata被引用兩次。

如何爲第一個線程(程序本身)加載PT_TLSPT_LOAD.tbss在哪裏?

+0

看起來像tls放在HEAP上... – osgx 2010-12-17 17:42:39

+0

你可以通過strace grepping來檢查'set_thread_area'系統調用 – osgx 2010-12-17 17:54:50

回答

3

第一個.tdata部分 - 是TLS數據的「初始圖像」。它是TLS變量的初始值,將在每個線程中使用(也在主線程中)。在crt(我認爲)有一個TLS初始圖像複製到主線程的TLS。相同的代碼在pthread_create

PT_TLS未加載,因爲PT_LOAD和PT_LOAD已經包含此PT_TLS。我認爲PT_TLS用於初始圖像 - 因爲它比整個線程本地數據(tbss + tdata> size(PT_TLS))短。

2

TLS代表「線程局部存儲」。

爲了允許在編譯時分配的數據與單獨的執行線程相關聯,可以使用線程本地存儲段來指定這些數據的大小和初始內容。實現不需要支持線程本地存儲。 PT_TLS程序條目具有以下成員:

Member  Value 
p_offset File offset of the TLS initialization image 
p_vaddr Virtual memory address of the TLS initialization image 
p_paddr reserved 
p_filesz Size of the TLS initialization image 
p_memsz Total size of the TLS template 
p_flags PF_R 
p_align Alignment of the TLS template 

TLS模板由標誌爲SHF_TLS的所有部分組合而成。保存初始化數據的TLS模板部分是TLS初始化圖像。 (TLS模板的其餘部分是SHT_NOBITS類型的一個或多個部分。)

+0

ok。但「第一個線程(程序本身)如何加載PT_TLS和PT_LOAD?」是個問題。 – osgx 2011-05-22 19:42:16

2

就映射內存區域而言,我認爲內核只查看PT_LOAD段和mmap。 (內核也會查看PT_GNU_STACK來判斷堆棧是否應該與Execute權限進行映射。)查看binfmt_elf.c:load_elf_binary()獲取相關代碼。

通過libc讀取PT_TLS段以找出要設置線程本地存儲的內存。查看相關代碼的__libc_setup_tls()。

PT_TLS段與PT_LOAD段相交,因此它被映射到進程內存中。