C 是否可能知道变量所在的内存段?

C 是否可能知道变量所在的内存段?,c,C,在C程序中有没有办法知道变量所在的部分?例如: char* str = "Word1"; char str2[] = "Word2"; printf("String1: %s | Location: %p\n", str, str); // <-- would be on the stack printf("String2: %s | Location: %p\n", str2, s

在C程序中有没有办法知道变量所在的部分?例如:

char*   str     = "Word1";
char    str2[]  = "Word2";


printf("String1: %s | Location: %p\n", str, str);   // <-- would be on the stack
printf("String2: %s | Location: %p\n", str2, str2); // <-- would be in .rodata
etc.
char*str=“Word1”;
字符str2[]=“Word2”;

printf(“String1:%s |位置:%p\n”,str,str);// C程序不可能绝对确定地知道其变量所在的部分。这就像海森堡测不准原理一样——仅仅获取一个变量的地址就可以使它存在于内存中,否则它可以通过优化完全消除

因此,使用
readelf
gdb
objdump
,他们正在解码实际的可执行文件


原则上,ELF头应该加载到内存中,您可以从中推断出部分,您可以在Linux上阅读
/proc/xx/maps
,等等,但是。。。除非我真的试图编写一个调试器、一个垃圾收集器或诸如此类的东西,否则我不会麻烦。

部分取决于实现,我将重点介绍
gcc
。您可以归档它,但它需要一些努力

  • 如果您使用自己的链接器脚本,请跳过此步骤。提取链接器脚本:
    ld--verbose>myls.ld
    。该文件将包含比仅线性脚本更多的信息,因此需要对其进行编辑
  • 我的默认链接器脚本:

    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/lib/x86_64-linux-gnu64"); 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
    {
      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 = .);
        }
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      .init           :
      {
        KEEP (*(SORT_NONE(.init)))
      }
      .plt            : { *(.plt) *(.iplt) }
    .plt.got        : { *(.plt.got) }
    .plt.sec        : { *(.plt.sec) }
      .text           :
      {
        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
        *(.text.exit .text.exit.*)
        *(.text.startup .text.startup.*)
        *(.text.hot .text.hot.*)
        *(SORT(.text.sorted.*))
        *(.text .stub .text.* .gnu.linkonce.t.*)
        /* .gnu.warning sections are handled specially by elf.em.  */
        *(.gnu.warning)
      }
      .fini           :
      {
        KEEP (*(SORT_NONE(.fini)))
      }
      PROVIDE (__etext = .);
      PROVIDE (_etext = .);
      PROVIDE (etext = .);
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      /* Adjust the address for the rodata segment.  We want to adjust up to
         the same address within the page on the next page up.  */
      . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
      PROVIDE(_RODATA_S = .);
      .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
      .rodata1        : { *(.rodata1) }
      PROVIDE(_RODATA_E = .);
      .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*) }
      /* 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*) }
      /* Thread Local Storage sections  */
      .tdata      :
       {
         PROVIDE_HIDDEN (__tdata_start = .);
         *(.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 = .;
      .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 do not
          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 = .);
      . = 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) }
      .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
      /* 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) }
      .debug_addr     0 : { *(.debug_addr) }
      .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
      /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
    }
    
  • 编辑链接器脚本:
  • 在要检查的部分的开头和结尾添加符号。默认链接器脚本很可能已经添加了这些符号

    在我的示例中,我将添加符号。这里是我为
    .rodata
    段添加的内容。您需要为要跟踪的所有部分添加符号

      PROVIDE(_RODATA_S = .);   // <-- added
      .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
      .rodata1        : { *(.rodata1) }
      PROVIDE(_RODATA_E = .);   // <-- added
    
    PS链接器脚本及其修改:

    
    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/lib/x86_64-linux-gnu64"); 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
    {
      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 = .);
        }
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      .init           :
      {
        KEEP (*(SORT_NONE(.init)))
      }
      .plt            : { *(.plt) *(.iplt) }
    .plt.got        : { *(.plt.got) }
    .plt.sec        : { *(.plt.sec) }
      .text           :
      {
        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
        *(.text.exit .text.exit.*)
        *(.text.startup .text.startup.*)
        *(.text.hot .text.hot.*)
        *(SORT(.text.sorted.*))
        *(.text .stub .text.* .gnu.linkonce.t.*)
        /* .gnu.warning sections are handled specially by elf.em.  */
        *(.gnu.warning)
      }
      .fini           :
      {
        KEEP (*(SORT_NONE(.fini)))
      }
      PROVIDE (__etext = .);
      PROVIDE (_etext = .);
      PROVIDE (etext = .);
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      /* Adjust the address for the rodata segment.  We want to adjust up to
         the same address within the page on the next page up.  */
      . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
      PROVIDE(_RODATA_S = .);
      .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
      .rodata1        : { *(.rodata1) }
      PROVIDE(_RODATA_E = .);
      .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*) }
      /* 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*) }
      /* Thread Local Storage sections  */
      .tdata      :
       {
         PROVIDE_HIDDEN (__tdata_start = .);
         *(.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) }
      PROVIDE(_DATA_S = .);
      .data           :
      {
        *(.data .data.* .gnu.linkonce.d.*)
        SORT(CONSTRUCTORS)
      }
      .data1          : { *(.data1) }
      _edata = .; PROVIDE (edata = .);
      . = .;
      __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 do not
          pad the .data section.  */
       . = ALIGN(. != 0 ? 64 / 8 : 1);
      }
      __bss_end = .;
      .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 = .);
      . = 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) }
      .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
      /* 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) }
      .debug_addr     0 : { *(.debug_addr) }
      .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
      /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
    }
    

    IIRC[我可能错了],没有去除调试/符号信息的ELF二进制文件将其与程序代码等一起映射到内存中(即,整个ELF文件被映射)。而且,
    libelf
    [和/或
    libdl
    ]可以达到这个目的。但是,在包装器脚本中捕获和解析
    readelf
    的输出并将输出文本文件传递给程序可能更容易。我真的做过那种[疯狂的]事情。但是,这是工作,所以一定要确定你真的想去做。@samuelbrody1249这可以通过一些努力和知识来完成。它可以像我的回答中那样存档。当然,方法可能会因使用的工具链而异感谢您提供这个非常详细的答案!如果可以这样称呼的话,链接器脚本是用什么语言编写的?用它自己的语言编写的
    x points to .rodata
    y points to .data
    y is located in .data
    fp points to .text
    fp is located in .data
    fp1 points to .text
    fp1 is located in unknown
    
    
    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/lib/x86_64-linux-gnu64"); 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
    {
      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 = .);
        }
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      .init           :
      {
        KEEP (*(SORT_NONE(.init)))
      }
      .plt            : { *(.plt) *(.iplt) }
    .plt.got        : { *(.plt.got) }
    .plt.sec        : { *(.plt.sec) }
      .text           :
      {
        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
        *(.text.exit .text.exit.*)
        *(.text.startup .text.startup.*)
        *(.text.hot .text.hot.*)
        *(SORT(.text.sorted.*))
        *(.text .stub .text.* .gnu.linkonce.t.*)
        /* .gnu.warning sections are handled specially by elf.em.  */
        *(.gnu.warning)
      }
      .fini           :
      {
        KEEP (*(SORT_NONE(.fini)))
      }
      PROVIDE (__etext = .);
      PROVIDE (_etext = .);
      PROVIDE (etext = .);
      . = ALIGN(CONSTANT (MAXPAGESIZE));
      /* Adjust the address for the rodata segment.  We want to adjust up to
         the same address within the page on the next page up.  */
      . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
      PROVIDE(_RODATA_S = .);
      .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
      .rodata1        : { *(.rodata1) }
      PROVIDE(_RODATA_E = .);
      .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*) }
      /* 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*) }
      /* Thread Local Storage sections  */
      .tdata      :
       {
         PROVIDE_HIDDEN (__tdata_start = .);
         *(.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) }
      PROVIDE(_DATA_S = .);
      .data           :
      {
        *(.data .data.* .gnu.linkonce.d.*)
        SORT(CONSTRUCTORS)
      }
      .data1          : { *(.data1) }
      _edata = .; PROVIDE (edata = .);
      . = .;
      __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 do not
          pad the .data section.  */
       . = ALIGN(. != 0 ? 64 / 8 : 1);
      }
      __bss_end = .;
      .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 = .);
      . = 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) }
      .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
      /* 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) }
      .debug_addr     0 : { *(.debug_addr) }
      .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
      /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
    }