C语⾔引⽤链接脚本中定义的符号
1. 使⽤ld --verbose 查看当前编译器默认的链接脚本:
default.ld
/* GNU ld (GNU Binutils for Ubuntu) 2.26.1
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
elf_iamcu
i386linux
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script: */
/* ================================================= */
/* Script for -z combreloc: combine and sort reloc sections */
/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/us r/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEAR CH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADER S;
.interp : { *(.interp) }
.u.build-id : { *(.u.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(. .* .*)
*(.rela.fini)
*(.data .data.* .*)
*(.rela.data .rela.data.* .u.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .u.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .u.linkonce.tb.*)
*(.s)
*(.rela.dtors)
*(.)
*(.rela.bss .rela.bss.* .u.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .u.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .u.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .u.linkonce.lr.*)
*(.rela.ifunc)
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
. : { *(.) }
.plt.bnd : { *(.plt.bnd) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.it .it.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .*)
/* .gnu.warning sections are handled specially */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.
rodata : { *(.rodata .rodata.* .*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); /* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
gnu编译器wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.
jcr : { KEEP (*(.jcr)) }
. : { *(.local* .gnu.l.ro.local.*) *(. .* .gnu.l.ro.*) } .dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start_xxdk =.; --->>> 添加⾃定义符号 <<<---
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.
bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.
lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : {
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : {
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
__bss_end_xxdk =.; --->>> 添加⾃定义符号 <<<---
. = DATA_SEGMENT_END (.);
/
* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.l 0 : { *(.l) }
.lstr 0 : { *(.lstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
ment 0 : { *(ment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/
* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.
debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/
* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
/*================================================== */
__bss_start_xxdk =; --->>> 添加⾃定义符号, <<<---
__bss_end_xxdk =.; --->>> 添加⾃定义符号 <<<---
在符号表中创建项,__bss_start_xxdk, 其持有当前内存位置(地址)“.”,但是该内存位置中没有存放任何有效的值。也就是说,不能访问⼀个链接脚本中定义的符号的“值”,它没有有效值。只能使⽤链接脚本中定义符号的地址;
因此在源码中使⽤链接脚本定义的符号,应该使⽤该符号的地址,⽽不是试图访问该符号的地址中的值;
3. 源码中使⽤链接脚本中定义的符号:
#include <stdio.h>
extern long __bss_start_xxdk, __bss_end_xxdk;
int main()
{
/**< 定义符号a, 符号表中添加⼀项名称为a,并且在内存中预留以&a起始, 长度sizeof(int)空间 */
int a;
a =10;///< 向符号a对应的内存地址&a中写⼊值10;
int* p;///< 定义符号p,符号表中添加⼀项名称为p, 并在内存中预留以&p起始,长度为sizeof(int*)的空间
p =&a;///< 向符号p对应的内存地址&p中写⼊符号a的起始地址&a
int b =*p;///< 解引⽤符号p对应内存地址&p中的值(即&a), 相当于 int b = *(&a);
b = a;///< 向符号b对应的内存地址&b中写⼊符号a的内存地址&a中的值
int** pp;///< 定义符号pp,符号表中添加⼀项名称为pp, 并在内存中预留以&pp起始,长度为sizeof(int*)的空间
pp =&p;///< 向符号pp对应的内存地址&pp中写⼊符号p的内存起始地址&p
*pp =0x10000000;///< 向符号pp对应的内存地址&pp中的值,写⼊0x10000000
该值为上⼀步存放的符号p的内存起始地址&p,相当于:&p =0x10000000,也就是我们改变了符号p的内存起始地址到0x10000000
/
**< -------------------------------------------------------------*/
/**< access the value at symbol __bss_start_xxdk memory's address:
long v = __bss_start_xxdk; 访问符号__bss_start_xxdk的内存地址中的值 */
long v = __bss_start_xxdk;
printf("%ld\n", v);///< zero
/**< access symbol __bss_start_xxdk memory's address:
we need this symbol address 访问符号__bss_start_xxdk的内存地址 */
long* p =&__bss_start_xxdk;///< 使⽤C语⾔标准语法访问符号的地址
printf("%p\n", p);
p =&__bss_end_xxdk;
printf("%p\n", p);
return0;
}
编译: gcc elf.c -T default.ld 让链接器使⽤我们修改过的默认脚本
运⾏./a.out:
0x601038
0x601040
查看符号表: objdump -h a.out | grep xxdk
0000000000601040 g .bss 0000000000000000 __bss_end_xxdk
0000000000601038 g .bss 0000000000000000 __bss_start_xxdk
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论