有没有办法在运行时找到代码段(.data、.text 等)的地址?
Is there a way to find addresses of the code sections (.data, .text, etc) at runtime?
我想写一些代码,在 运行 时在它自己的进程中打印每个代码段的地址和长度。是否有捷径可寻?我知道使用 void* main_address = main;
之类的代码找到 main 等函数的位置相对容易,但我想找到 .data 和 .text 之类的部分,但我不知道我是否可以用它们做同样的事情当我编译时。我正在 Windows 系统上编写此实验并针对 x86 架构进行编译。如果解决方案需要的话,我知道一些 x86 程序集。我真的很感激任何帮助或建议。谢谢!
我不知道 Windows 约定,但如果它类似于 Linux,您的编译器、汇编器或链接器可能会为节的开头定义一个符号。 (使用 nm
或类似工具从 .obj
或 .exe
转储符号 table。)
如果是这样,extern const char that_symbol[]
将定义一个可能匹配名称的 C 变量。那么当然你可以只使用that_symbol
的地址。 (注意,不是 const char *that_symbol
;内存中没有存储指针。您正在定义一个静态变量,其 address 是您想要的地址。不要阅读 这个变量的值。)
如果需要绕过前导下划线或使用包含 .
或 C 不允许的内容的汇编符号名称,请使用 GNU C extern char foo[] asm("real_name")
。 https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html 这当然是一个 GNU 扩展。
请参阅 以了解此答案所建议内容的完整 Windows 实现 ,包括 GNU binutils 链接器脚本以添加缺少的符号 starts/ends 工具链未自行定义的某些部分。它使用 extern char
而不是 extern char[]
作为 C 名称,因此您必须始终使用 &name
来获取符号的地址。但是定义具有您想要的地址的 C extern
全局变量的基本思想正是我所建议的。
That depends on the compiler used. This will be about the gcc & binutils.
- Find your project linker script. The linker script usually has the
.ld
file extension. If there is no linker script your project uses the default one. To see the default linker script you need to pass -Wl,--verbose
. You will see a lot of information but we are looking for something like this (this is my one):
/* Default linker script, for normal executables */
/* Copyright (C) 2014 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(pei-i386)
SEARCH_DIR("/mingw/mingw32/lib"); SEARCH_DIR("/mingw/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Make the virtual address and file offset synced if the alignment is
lower than the target page size. */
. = SIZEOF_HEADERS;
. = ALIGN(__section_alignment__);
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
{
*(.init)
*(.text)
*(SORT(.text$*))
*(.text.*)
*(.gnu.linkonce.t.*)
*(.glue_7t)
*(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);
*(.fini)
/* ??? Why is .gcc_exc here? */
*(.gcc_exc)
PROVIDE (etext = .);
PROVIDE (_etext = .);
*(.gcc_except_table)
}
/* The Cygwin32 library uses a section to avoid copying certain data
on fork. This used to be named ".data". The linker used
to include this between __data_start__ and __data_end__, but that
breaks building the cygwin32 dll. Instead, we name the section
".data_cygwin_nocopy" and explicitly include it after __data_end__. */
.data BLOCK(__section_alignment__) :
{
__data_start__ = . ;
*(.data)
*(.data2)
*(SORT(.data$*))
*(.jcr)
__data_end__ = . ;
*(.data_cygwin_nocopy)
}
.rdata BLOCK(__section_alignment__) :
{
*(.rdata)
*(SORT(.rdata$*))
__rt_psrelocs_start = .;
*(.rdata_runtime_pseudo_reloc)
__rt_psrelocs_end = .;
}
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
.eh_frame BLOCK(__section_alignment__) :
{
*(.eh_frame*)
}
.pdata BLOCK(__section_alignment__) :
{
*(.pdata)
}
.bss BLOCK(__section_alignment__) :
{
__bss_start__ = . ;
*(.bss)
*(COMMON)
__bss_end__ = . ;
}
.edata BLOCK(__section_alignment__) :
{
*(.edata)
}
/DISCARD/ :
{
*(.debug$S)
*(.debug$T)
*(.debug$F)
*(.drectve)
*(.note.GNU-stack)
*(.gnu.lto_*)
}
.idata BLOCK(__section_alignment__) :
{
/* This cannot currently be handled with grouped sections.
See pe.em:sort_sections. */
SORT(*)(.idata)
SORT(*)(.idata)
/* These zeroes mark the end of the import list. */
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
SORT(*)(.idata)
__IAT_start__ = .;
SORT(*)(.idata)
__IAT_end__ = .;
SORT(*)(.idata)
SORT(*)(.idata)
}
.CRT BLOCK(__section_alignment__) :
{
___crt_xc_start__ = . ;
*(SORT(.CRT$XC*)) /* C initialization */
___crt_xc_end__ = . ;
___crt_xi_start__ = . ;
*(SORT(.CRT$XI*)) /* C++ initialization */
___crt_xi_end__ = . ;
___crt_xl_start__ = . ;
*(SORT(.CRT$XL*)) /* TLS callbacks */
/* ___crt_xl_end__ is defined in the TLS Directory support code */
___crt_xp_start__ = . ;
*(SORT(.CRT$XP*)) /* Pre-termination */
___crt_xp_end__ = . ;
___crt_xt_start__ = . ;
*(SORT(.CRT$XT*)) /* Termination */
___crt_xt_end__ = . ;
}
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be
at the end of section. This is important because _tls_start MUST
be at the beginning of the section to enable SECREL32 relocations with TLS
data. */
.tls BLOCK(__section_alignment__) :
{
___tls_start__ = . ;
*(.tls$AAA)
*(.tls)
*(.tls$)
*(SORT(.tls$*))
*(.tls$ZZZ)
___tls_end__ = . ;
}
.endjunk BLOCK(__section_alignment__) :
{
/* end is deprecated, don't use it */
PROVIDE (end = .);
PROVIDE ( _end = .);
__end__ = .;
}
.rsrc BLOCK(__section_alignment__) : SUBALIGN(4)
{
*(.rsrc)
*(.rsrc$*)
}
.reloc BLOCK(__section_alignment__) :
{
*(.reloc)
}
.stab BLOCK(__section_alignment__) (NOLOAD) :
{
*(.stab)
}
.stabstr BLOCK(__section_alignment__) (NOLOAD) :
{
*(.stabstr)
}
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section. Unlike other targets that fake this by putting the
section VMA at 0, the PE format will not allow it. */
/* DWARF 1.1 and DWARF 2. */
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_aranges)
}
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_aranges)
}
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubnames)
}
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_pubnames)
}
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubtypes)
}
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_pubtypes)
}
/* DWARF 2. */
.debug_info BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_info .gnu.linkonce.wi.*)
}
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)
}
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_abbrev)
}
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_abbrev)
}
.debug_line BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_line)
}
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_line)
}
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_frame*)
}
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_frame*)
}
.debug_str BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_str)
}
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_str)
}
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_loc)
}
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_loc)
}
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macinfo)
}
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_macinfo)
}
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_weaknames)
}
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_weaknames)
}
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_funcnames)
}
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_funcnames)
}
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_typenames)
}
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_typenames)
}
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_varnames)
}
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_varnames)
}
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macro)
}
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_macro)
}
/* DWARF 3. */
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_ranges)
}
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_ranges)
}
/* DWARF 4. */
.debug_types BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_types .gnu.linkonce.wt.*)
}
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_types .gnu.linkonce.wt.*)
}
}
Copy and paste it to the text file (.ld extension will help you or other people to understand what this file does).
As we see the .text
section does provide two symbols at the end, but there is no symbol at the beginning. We can add this symbol ourselves:
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
{
.__text_start__ = .;
*(.init)
You need to pass -Tpath_to_your_ld_file
to the linker
then in the .c file we can test it:
extern char _text_start__, etext, _data_start__, _data_end__, _bss_start__, _bss_end__;
int main()
{
printf("Text start: %p Text end: %p\n", (void *)&_text_start__, (void *)&etext);
printf("Data start: %p Data end: %p\n", (void *)&_data_start__, (void *)&_data_end__);
printf("BSS start: %p BSS end: %p\n", (void *)&_bss_start__, (void *)&_bss_end__);
}
on my computer it is:
Text start: 00401000 Text end: 00408FF4
Data start: 00409000 Data end: 0040902C
BSS start: 0040D000 BSS end: 0040DA34
只需走过PIMAGE_SECTION_HEADER
秒
void DumpSections()
{
//PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)((PBYTE)&__ImageBase + reinterpret_cast<PIMAGE_DOS_HEADER>(&__ImageBase)->e_lfanew);
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(&__ImageBase))
{
if (ULONG NumberOfSections = pinth->FileHeader.NumberOfSections)
{
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);
do
{
DbgPrint("%p %08x %.8s\n", (PBYTE)&__ImageBase + pish->VirtualAddress, pish->Misc.VirtualSize, pish->Name);
} while (pish++, --NumberOfSections);
}
}
}
我想写一些代码,在 运行 时在它自己的进程中打印每个代码段的地址和长度。是否有捷径可寻?我知道使用 void* main_address = main;
之类的代码找到 main 等函数的位置相对容易,但我想找到 .data 和 .text 之类的部分,但我不知道我是否可以用它们做同样的事情当我编译时。我正在 Windows 系统上编写此实验并针对 x86 架构进行编译。如果解决方案需要的话,我知道一些 x86 程序集。我真的很感激任何帮助或建议。谢谢!
我不知道 Windows 约定,但如果它类似于 Linux,您的编译器、汇编器或链接器可能会为节的开头定义一个符号。 (使用 nm
或类似工具从 .obj
或 .exe
转储符号 table。)
如果是这样,extern const char that_symbol[]
将定义一个可能匹配名称的 C 变量。那么当然你可以只使用that_symbol
的地址。 (注意,不是 const char *that_symbol
;内存中没有存储指针。您正在定义一个静态变量,其 address 是您想要的地址。不要阅读 这个变量的值。)
如果需要绕过前导下划线或使用包含 .
或 C 不允许的内容的汇编符号名称,请使用 GNU C extern char foo[] asm("real_name")
。 https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html 这当然是一个 GNU 扩展。
请参阅 extern char
而不是 extern char[]
作为 C 名称,因此您必须始终使用 &name
来获取符号的地址。但是定义具有您想要的地址的 C extern
全局变量的基本思想正是我所建议的。
That depends on the compiler used. This will be about the gcc & binutils.
- Find your project linker script. The linker script usually has the
.ld
file extension. If there is no linker script your project uses the default one. To see the default linker script you need to pass-Wl,--verbose
. You will see a lot of information but we are looking for something like this (this is my one):
/* Default linker script, for normal executables */
/* Copyright (C) 2014 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(pei-i386)
SEARCH_DIR("/mingw/mingw32/lib"); SEARCH_DIR("/mingw/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Make the virtual address and file offset synced if the alignment is
lower than the target page size. */
. = SIZEOF_HEADERS;
. = ALIGN(__section_alignment__);
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
{
*(.init)
*(.text)
*(SORT(.text$*))
*(.text.*)
*(.gnu.linkonce.t.*)
*(.glue_7t)
*(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);
*(.fini)
/* ??? Why is .gcc_exc here? */
*(.gcc_exc)
PROVIDE (etext = .);
PROVIDE (_etext = .);
*(.gcc_except_table)
}
/* The Cygwin32 library uses a section to avoid copying certain data
on fork. This used to be named ".data". The linker used
to include this between __data_start__ and __data_end__, but that
breaks building the cygwin32 dll. Instead, we name the section
".data_cygwin_nocopy" and explicitly include it after __data_end__. */
.data BLOCK(__section_alignment__) :
{
__data_start__ = . ;
*(.data)
*(.data2)
*(SORT(.data$*))
*(.jcr)
__data_end__ = . ;
*(.data_cygwin_nocopy)
}
.rdata BLOCK(__section_alignment__) :
{
*(.rdata)
*(SORT(.rdata$*))
__rt_psrelocs_start = .;
*(.rdata_runtime_pseudo_reloc)
__rt_psrelocs_end = .;
}
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
.eh_frame BLOCK(__section_alignment__) :
{
*(.eh_frame*)
}
.pdata BLOCK(__section_alignment__) :
{
*(.pdata)
}
.bss BLOCK(__section_alignment__) :
{
__bss_start__ = . ;
*(.bss)
*(COMMON)
__bss_end__ = . ;
}
.edata BLOCK(__section_alignment__) :
{
*(.edata)
}
/DISCARD/ :
{
*(.debug$S)
*(.debug$T)
*(.debug$F)
*(.drectve)
*(.note.GNU-stack)
*(.gnu.lto_*)
}
.idata BLOCK(__section_alignment__) :
{
/* This cannot currently be handled with grouped sections.
See pe.em:sort_sections. */
SORT(*)(.idata)
SORT(*)(.idata)
/* These zeroes mark the end of the import list. */
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
SORT(*)(.idata)
__IAT_start__ = .;
SORT(*)(.idata)
__IAT_end__ = .;
SORT(*)(.idata)
SORT(*)(.idata)
}
.CRT BLOCK(__section_alignment__) :
{
___crt_xc_start__ = . ;
*(SORT(.CRT$XC*)) /* C initialization */
___crt_xc_end__ = . ;
___crt_xi_start__ = . ;
*(SORT(.CRT$XI*)) /* C++ initialization */
___crt_xi_end__ = . ;
___crt_xl_start__ = . ;
*(SORT(.CRT$XL*)) /* TLS callbacks */
/* ___crt_xl_end__ is defined in the TLS Directory support code */
___crt_xp_start__ = . ;
*(SORT(.CRT$XP*)) /* Pre-termination */
___crt_xp_end__ = . ;
___crt_xt_start__ = . ;
*(SORT(.CRT$XT*)) /* Termination */
___crt_xt_end__ = . ;
}
/* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be
at the end of section. This is important because _tls_start MUST
be at the beginning of the section to enable SECREL32 relocations with TLS
data. */
.tls BLOCK(__section_alignment__) :
{
___tls_start__ = . ;
*(.tls$AAA)
*(.tls)
*(.tls$)
*(SORT(.tls$*))
*(.tls$ZZZ)
___tls_end__ = . ;
}
.endjunk BLOCK(__section_alignment__) :
{
/* end is deprecated, don't use it */
PROVIDE (end = .);
PROVIDE ( _end = .);
__end__ = .;
}
.rsrc BLOCK(__section_alignment__) : SUBALIGN(4)
{
*(.rsrc)
*(.rsrc$*)
}
.reloc BLOCK(__section_alignment__) :
{
*(.reloc)
}
.stab BLOCK(__section_alignment__) (NOLOAD) :
{
*(.stab)
}
.stabstr BLOCK(__section_alignment__) (NOLOAD) :
{
*(.stabstr)
}
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section. Unlike other targets that fake this by putting the
section VMA at 0, the PE format will not allow it. */
/* DWARF 1.1 and DWARF 2. */
.debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_aranges)
}
.zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_aranges)
}
.debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubnames)
}
.zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_pubnames)
}
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubtypes)
}
.zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_pubtypes)
}
/* DWARF 2. */
.debug_info BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_info .gnu.linkonce.wi.*)
}
.zdebug_info BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_info .zdebug.gnu.linkonce.wi.*)
}
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_abbrev)
}
.zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_abbrev)
}
.debug_line BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_line)
}
.zdebug_line BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_line)
}
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_frame*)
}
.zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_frame*)
}
.debug_str BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_str)
}
.zdebug_str BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_str)
}
.debug_loc BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_loc)
}
.zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_loc)
}
.debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macinfo)
}
.zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_macinfo)
}
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_weaknames)
}
.zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_weaknames)
}
.debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_funcnames)
}
.zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_funcnames)
}
.debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_typenames)
}
.zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_typenames)
}
.debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_varnames)
}
.zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_varnames)
}
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macro)
}
.zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_macro)
}
/* DWARF 3. */
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_ranges)
}
.zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_ranges)
}
/* DWARF 4. */
.debug_types BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_types .gnu.linkonce.wt.*)
}
.zdebug_types BLOCK(__section_alignment__) (NOLOAD) :
{
*(.zdebug_types .gnu.linkonce.wt.*)
}
}
Copy and paste it to the text file (.ld extension will help you or other people to understand what this file does).
As we see the .text
section does provide two symbols at the end, but there is no symbol at the beginning. We can add this symbol ourselves:
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
{
.__text_start__ = .;
*(.init)
You need to pass -Tpath_to_your_ld_file
to the linker
then in the .c file we can test it:
extern char _text_start__, etext, _data_start__, _data_end__, _bss_start__, _bss_end__;
int main()
{
printf("Text start: %p Text end: %p\n", (void *)&_text_start__, (void *)&etext);
printf("Data start: %p Data end: %p\n", (void *)&_data_start__, (void *)&_data_end__);
printf("BSS start: %p BSS end: %p\n", (void *)&_bss_start__, (void *)&_bss_end__);
}
on my computer it is:
Text start: 00401000 Text end: 00408FF4
Data start: 00409000 Data end: 0040902C
BSS start: 0040D000 BSS end: 0040DA34
只需走过PIMAGE_SECTION_HEADER
秒
void DumpSections()
{
//PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)((PBYTE)&__ImageBase + reinterpret_cast<PIMAGE_DOS_HEADER>(&__ImageBase)->e_lfanew);
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(&__ImageBase))
{
if (ULONG NumberOfSections = pinth->FileHeader.NumberOfSections)
{
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);
do
{
DbgPrint("%p %08x %.8s\n", (PBYTE)&__ImageBase + pish->VirtualAddress, pish->Misc.VirtualSize, pish->Name);
} while (pish++, --NumberOfSections);
}
}
}