我是靠谱客的博主 真实玉米,最近开发中收集的这篇文章主要介绍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("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_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_HEADERS;
.interp
: { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.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.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt
:
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.init
:
{
KEEP (*(SORT_NONE(.init)))
}
.plt
: { *(.plt) *(.iplt) }
.plt.got
: { *(.plt.got) }
.plt.bnd
: { *(.plt.bnd) }
.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) }
.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 = .);
}
.fini_array
:
{
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
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)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.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);
}
.lbss
:
{
*(.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) }
.stab.excl
0 : { *(.stab.excl) }
.stab.exclstr
0 : { *(.stab.exclstr) }
.stab.index
0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment
0 : { *(.comment) }
/* 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_*) }
}
/*================================================== */

2. 在上述默认链接脚本中添加了两个自定义的符号:

__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("%ldn", 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("%pn", p);
p = &__bss_end_xxdk;
printf("%pn", p);
return 0;
}
  • 编译: gcc elf.c -T default.ld 让链接器使用我们修改过的默认脚本
  • 运行./a.out:
0
0x601038
0x601040
  • 查看符号表: objdump -h a.out | grep xxdk
0000000000601040 g
.bss	0000000000000000
__bss_end_xxdk
0000000000601038 g
.bss	0000000000000000
__bss_start_xxdk

最后

以上就是真实玉米为你收集整理的C语言引用链接脚本中定义的符号的全部内容,希望文章能够帮你解决C语言引用链接脚本中定义的符号所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部