And*_* B. 11 c linker gcc visual-c++
我正在编写一些代码,它将一些数据结构存储在一个特殊的命名二进制部分中.这些是同一结构的所有实例,它们分散在许多C文件中,并且不在彼此的范围内.通过将它们全部放在命名区域中,我可以遍历所有这些区域.
在GCC中,我使用_ attribute _((section(...))加上一些特别命名的extern指针,这些指针由链接器神奇地填充.这是一个简单的例子:
#include <stdio.h>
extern int __start___mysection[];
extern int __stop___mysection[];
static int x __attribute__((section("__mysection"))) = 4;
static int y __attribute__((section("__mysection"))) = 10;
static int z __attribute__((section("__mysection"))) = 22;
#define SECTION_SIZE(sect) \
((size_t)((__stop_##sect - __start_##sect)))
int main(void)
{
size_t sz = SECTION_SIZE(__mysection);
int i;
printf("Section size is %u\n", sz);
for (i=0; i < sz; i++) {
printf("%d\n", __start___mysection[i]);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我试图找出如何在MSVC中做到这一点,但我画了一个空白.我从编译器文档中看到我可以使用__pragma(section(...))声明该部分,并使用__declspec(allocate(...))声明数据在该部分中,但我看不出我怎么能得到在运行时指向节的开始和结束的指针.
我在Web上看到了一些与在MSVC中执行_ attribute _((构造函数))相关的示例,但它似乎是特定于CRT的黑客攻击,而不是获取指向节的开头/结尾的指针的一般方法.有人有主意吗?
小智 7
还有一种方法可以使用汇编文件来完成此操作.
#pragma section(".init$a")
#pragma section(".init$u")
#pragma section(".init$z")
__declspec(allocate(".init$a")) int InitSectionStart = 0;
__declspec(allocate(".init$z")) int InitSectionEnd = 0;
__declspec(allocate(".init$u")) int token1 = 0xdeadbeef;
__declspec(allocate(".init$u")) int token2 = 0xdeadc0de;
Run Code Online (Sandbox Code Playgroud)
前3行定义了段.这些定义了部分并取代了程序集文件.与data_seg pragma不同,section pragma仅创建节.__declspec(allocate())行告诉编译器将该项放在该段中.
从微软页面:这里的顺序很重要.部分名称不得超过8个字符.$之前具有相同名称的部分合并为一个部分.它们合并的顺序是通过对$后面的字符进行排序来确定的.
要记住的另一个要点是段填充为256字节. START和END指针不会像你期望的那样直接在之前和之后.
如果将表设置为指向函数或其他非NULL值的指针,则应该很容易在表之前和之后跳过NULL条目,因为部分填充
有关更多详细信息,请参见此msdn页面
首先,您需要创建一个 ASM 文件,其中包含您感兴趣的所有部分(例如,section.asm):
.686
.model flat
PUBLIC C __InitSectionStart
PUBLIC C __InitSectionEnd
INIT$A SEGMENT DWORD PUBLIC FLAT alias(".init$a")
__InitSectionStart EQU $
INIT$A ENDS
INIT$Z SEGMENT DWORD PUBLIC FLAT alias(".init$z")
__InitSectionEnd EQU $
INIT$Z ENDS
END
Run Code Online (Sandbox Code Playgroud)
接下来,在您的代码中,您可以使用以下内容:
#pragma data_seg(".init$u")
int token1 = 0xdeadbeef;
int token2 = 0xdeadc0de;
#pragma data_seg()
Run Code Online (Sandbox Code Playgroud)
这给出了这样一个 MAP 文件:
Start Length Name Class
0003:00000000 00000000H .init$a DATA
0003:00000000 00000008H .init$u DATA
0003:00000008 00000000H .init$z DATA
Address Publics by Value Rva+Base Lib:Object
0003:00000000 ?token1@@3HA 10005000 dllmain.obj
0003:00000000 ___InitSectionStart 10005000 section.obj
0003:00000004 ?token2@@3HA 10005004 dllmain.obj
0003:00000008 ___InitSectionEnd 10005008 section.obj
Run Code Online (Sandbox Code Playgroud)
因此,如您所见,具有名称的部分.init$u位于.init$a和之间,.init$z这使您能够通过__InitSectionStart符号获取指向数据开头的指针和通过符号指向数据结尾的指针__InitSectionEnd。
| 归档时间: |
|
| 查看次数: |
2299 次 |
| 最近记录: |