原著:Bernd. Luevelsmeyer
翻译:ah007
[注意:本译文的所有大小标题序号都是译者添加,以方便大家阅读。圆圈内的数字是注释的编号,其中注释②译自微软的《PECOFF规范》,其它译自网络。----译者]
十一、Bug报告(Bug reports)
----------------------------
Bug报告(或其他建议)请发送至:bernd.luevelsmeyer@iplan.heitec.net
十二、版本(Versions)
----------------------
你可在文件的顶部找到当前的版本号。
1998-04-06
第一次公开发表
1998-07-29
将映象文件版本和子系统版本中错误的“byte”改为“word”
更正“栈只限于1 MB”的错误(实际上没有上限)
更正一些输入错误
1999-03-15
更正输出目录的描述,原来非常不全
调整输入目录的描述,原来讲的不清
更正输入错误并为其它节改了一些词句
十三、参考文献(Literature)
----------------------------
[1]
"Peering Inside the PE: A Tour of the Win32 Portable Executable File
Format" (M. Pietrek), in: Microsoft Systems Journal 3/1994
[2]
"Why to Use _declspec(dllimport) & _declspec(dllexport) In Code", MS
Knowledge Base Q132044
[3]《Windows 问与答》
"Windows Q&A" (M. Pietrek), in: Microsoft Systems Journal 8/1995
[4]《编写多语言资源》
"Writing Multiple-Language Resources", MS Knowledge Base Q89866
[5]
"The Portable Executable File Format from Top to Bottom" (Randy Kath),
in: Microsoft Developer Network
[6]《Windows下TIS格式规范1.0版》
Tool Interface Standard (TIS) Formats Specification for Windows Version
1.0 (Intel Order Number 241597, Intel Corporation 1993)
附录(Appendix: hello world):
-------------------------------
在这个附录中我将给大家展示一下怎样手工建立一个程序。因为我不会DEC Alpha的,本例将使用Intel汇编语言。
本程序相当于
#include
int main(void)
{
puts(hello,world);
return 0;
}
首先,我使用Win32函数来翻译它以取代C运行时库:
#define STD_OUTPUT_HANDLE -11UL
#define hello "hello, world\n"
__declspec(dllimport) unsigned long __stdcall
GetStdHandle(unsigned long hdl);
__declspec(dllimport) unsigned long __stdcall
WriteConsoleA(unsigned long hConsoleOutput,
const void *buffer,
unsigned long chrs,
unsigned long *written,
unsigned long unused
);
static unsigned long written;
void startup(void)
{
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),hello,sizeof(hello)-1,&written,0);
return;
}
现在我将笨拙的将它汇编出来:
startup:
; WriteConsole()的参数, 反向的
6A 00 push 0x00000000
68 ?? ?? ?? ?? push offset _written
6A 0D push 0x0000000d
68 ?? ?? ?? ?? push offset hello
; GetStdHandle()的参数
6A F5 push 0xfffffff5
2E FF 15 ?? ?? ?? ?? call dword ptr cs:__imp__GetStdHandle@4
; 结果是WriteConsole()的参数
50 push eax
2E FF 15 ?? ?? ?? ?? call dword ptr cs:__imp__WriteConsoleA@20
C3 ret
hello:
68 65 6C 6C 6F 2C 20 77 6F 72 6C 64 0A "hello, world\n"
_written:
00 00 00 00
以上就是编译的部分。任何人都能做到这点。从现在起让我们扮演起链接器的角色,这会非常有趣 :-)
我需要先找出函数WriteConsoleA()和GetStdHandle()。碰巧它们都在“kernel32.dll”中。(这是“输入库”部分。)
现在我开始做可执行文件。问号代表待定的值;它们将在以后被修正。
首先是DOS-根,开始于0x0,有0x40字节长:
00 | 4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30 | 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00
正如你所见到的,这不是真正的MS-DOS程序。它只是一个开始部分有“MZ”签名的头和紧跟在头后面的e_lfanew指针,没有任何代码。这是因为它并非打算运行于MS-DOS之上;它之所以在这里只是因为规范的需要。
然后是PE签名,开始于0x40,有0x4字节长:
50 45 00 00
现在到了文件头,开始于0x44,有0x14字节长:
Machine 4c 01 ; i386
NumberOfSections 02 00 ; 代码段和数据段
TimeDateStamp 00 00 00 00 ; 谁管它?
PointerToSymbolTable 00 00 00 00 ; 未用
NumberOfSymbols 00 00 00 00 ; 未用
Si
[1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页
