VC 2019安排代码位置

1. 问题的出现

这个问题是我在开发32位引导程序是出现的,原来是用VC2005来编译和链接的,一直工作很正常,但是,有一天,我突发奇想,换成VC2019来编译,好吧,引导程序就罢工了……

这是我的makefile

OBJS    = $(OBJDIR)\startup.obj $(OBJDIR)\rbxldr32.obj $(OBJDIR)\io.obj \
	$(OBJDIR)\nvsprintf.obj $(OBJDIR)\bvd.obj $(OBJDIR)\pe.obj
#
#
..\..\bin\RBXLDR32: $(OBJS) ..\..\bin\build.exe
    $(LINK) $(LFLAGS) $(OBJS) libc.lib msvcrt.lib
	del ..\..\bin\RBXLDR32
	..\..\bin\build -s..\..\bin\rbxldr32.exe -d..\..\bin\RBXLDR32 -a18000

我把mainCRTStartup放在startup.obj中,为了保证mainCRTStartup位于0x00401000的位置,我就把startup.obj放在了第一个文件中。这个makefile在VC2005中,没有问题。

换到了VC2019后,就不行了

折腾了半天,搞了各种编译和链接的参数,毛用都没有

2. 发现问题

然后就看MAP文件,一看,简直日了狗了,原来是入口点变了。我是设计将引导程序的入口点放在RVA+0x00001000处,经过重定位后,是在0x00019000处,在MAP文件中,会显示在0x00401000处。

这个安排在VC2005中并没有问题,到了VC2019,就出问题了,微软还真能搞事,

这个可以看看,先放VC2005的MAP文件

 rbxldr32
 
 Timestamp is 5e736e4f (Thu Mar 19 21:06:23 2020)
 
 Preferred load address is 00400000
 
 Start         Length     Name                   Class
 0001:00000000 00002e8cH .text                   CODE
 0002:00000000 00000790H .data                   DATA
 0002:000007a0 00000360H .bss                    DATA
 
  Address         Publics by Value              Rva+Base       Lib:Object

 0000:00000000       ___safe_se_handler_count   00000000     <absolute>
 0000:00000000       ___safe_se_handler_table   00000000     <absolute>
 0001:00000000       _mainCRTStartup            00401000 f   startup.obj
 0001:00000010       _CheckLdrParamList         00401010 f   rbxldr32.obj
 0001:00000120       _LPL_FindFirst             00401120 f   rbxldr32.obj
 0001:00000150       _LDR_GetSysImgOffset       00401150 f   rbxldr32.obj
  
 entry point at        0001:00000000

这个可以看出,mainCRTStartup就位于0x00401000处, 没有问题。

然后看看VC2019的MAP文件

 rbxldr32
 
 Timestamp is 5e736f05 (Thu Mar 19 21:09:25 2020)
 
 Preferred load address is 00400000

 Start         Length     Name                   Class
 0001:00000000 00000690H .text                   CODE
 0001:00000690 000027a5H .text$mn                CODE
 0002:00000000 0000001cH .rdata                  DATA
 0002:0000001c 00000000H .edata                  DATA
 0002:0000001c 00000070H .rdata$zzzdbg           DATA
 0003:00000000 000007a0H .data                   DATA
 0003:000007a0 00000374H .bss                    DATA
;
  Address         Publics by Value              Rva+Base       Lib:Object
;
 0000:00000000       ___guard_longjmp_table     00000000     <absolute>
 0000:00000000       ___guard_iat_table         00000000     <absolute>
 0001:00000000       _strcmp                    00401000 f   libc:strcmp.obj
 0001:00000090       _memset                    00401090 f   libc:memset.obj
 0001:000000f0       _strstr                    004010f0 f   libc:strstr.obj
 0001:00000170       _strlen                    00401170 f   libc:strlen.obj
 0001:000001f0       __aulldiv                  004011f0 f   libc:ulldiv.obj
 0001:00000260       __allmul                   00401260 f   libc:llmul.obj
 0001:000002a0       __aullrem                  004012a0 f   libc:ullrem.obj
 0001:00000320       _memmove                   00401320 f   libc:memmove.obj
 0001:00000470       _memcpy                    00401470 f   libc:memcpy.obj
 0001:000005d0       _strchr                    004015d0 f   libc:strchr.obj
 0001:000005d6       ___from_strstr_to_strchr   004015d6     libc:strchr.obj
 0001:00000690       _mainCRTStartup            00401690 f   startup.obj
 0001:000006a0       _CheckLdrParamList         004016a0 f   rbxldr32.obj
 0001:000007b0       _LPL_FindFirst             004017b0 f   rbxldr32.obj
 0001:000007e0       _LDR_GetSysImgOffset       004017e0 f   rbxldr32.obj
 0001:000008c0       _BuildSystMemLayout        004018c0 f   rbxldr32.obj
 
 entry point at        0001:00000690

0x00401000的位置居然变成了strcmp,那当然会出错了

3. 问题在哪里

一开始,还以为是链接器改变了按照目标文件和库文件顺序来安排代码位置的方式,但是,仔细一看,还是按照命令行指定的顺序来安排代码位置的。

找了很久,找不到,都要死心滚回VC2005了,在上下翻MAP文件的时候,发现了问题在哪里,居然是在死心后发现问题的,发现VC2019编译出的MAP存在特别多的节(SECTION),对比一下VC2005的MAP文件,VC2005编译出来只有3个节,而VC2019,居然编译出了7个节,而且居然还有两个代码节,日

; 这是VC2005的节信息
 Start         Length     Name                   Class
 0001:00000000 00002e8cH .text                   CODE
 0002:00000000 00000790H .data                   DATA
 0002:000007a0 00000360H .bss                    DATA
;
; 这是VC2019的节信息
 Start         Length     Name                   Class
 0001:00000000 00000690H .text                   CODE
 0001:00000690 000027a5H .text$mn                CODE
 0002:00000000 0000001cH .rdata                  DATA
 0002:0000001c 00000000H .edata                  DATA
 0002:0000001c 00000070H .rdata$zzzdbg           DATA
 0003:00000000 000007a0H .data                   DATA
 0003:000007a0 00000374H .bss                    DATA

然后还发现,VC2019居然把mainCRTStartup放在了第二个代码节的开头

 0001:00000690       _mainCRTStartup            00401690 f   startup.obj

到这里才发现,这是两个不同名称的代码节,什么鬼?编译器居然给代码节改名了……所以链接器就按节名称的顺序来安排代码位置,好吧,大写的服。

4. 解决问题

为了解决这个问题,我首先想到的是给代码节改名,改成.text应该就可以了,在CL.EXE的帮助里没有找到可以改节名的地方,是想在编译参数里面设置的话,可以映像到整个程序,没找到…

算了,还是老老实实用#pragma吧

就是在代码里增加一行 #pragma code_seg(".text")

修改后的代码是这样的

#include "rbxldr32.h"
void        main(void);
//
#pragma code_seg(".text")
//
void mainCRTStartup(void)
{
    main();
    for(;;)
        ;
}

然后来看看编译出来的MAP

rbxldr32
;
 Timestamp is 5e7375d3 (Thu Mar 19 21:38:27 2020)
;
 Preferred load address is 00400000
;
 Start         Length     Name                   Class
 0001:00000000 000006a0H .text                   CODE
 0001:000006a0 00002795H .text$mn                CODE
 0002:00000000 0000001cH .rdata                  DATA
 0002:0000001c 00000000H .edata                  DATA
 0002:0000001c 00000070H .rdata$zzzdbg           DATA
 0003:00000000 000007a0H .data                   DATA
 0003:000007a0 00000374H .bss                    DATA
;
  Address         Publics by Value              Rva+Base       Lib:Object
;
 0000:00000000       ___guard_longjmp_table     00000000     <absolute>
 0000:00000000       ___guard_iat_table         00000000     <absolute>
 0001:00000000       _mainCRTStartup            00401000 f   startup.obj
 0001:00000010       _strcmp                    00401010 f   libc:strcmp.obj
 0001:000000a0       _memset                    004010a0 f   libc:memset.obj
 0001:00000100       _strstr                    00401100 f   libc:strstr.obj
 0001:00000180       _strlen                    00401180 f   libc:strlen.obj
 0001:00000200       __aulldiv                  00401200 f   libc:ulldiv.obj
 0001:00000270       __allmul                   00401270 f   libc:llmul.obj
 0001:000002b0       __aullrem                  004012b0 f   libc:ullrem.obj
 0001:00000330       _memmove                   00401330 f   libc:memmove.obj
 0001:00000480       _memcpy                    00401480 f   libc:memcpy.obj
 0001:000005e0       _strchr                    004015e0 f   libc:strchr.obj
 0001:000005e6       ___from_strstr_to_strchr   004015e6     libc:strchr.obj
 0001:000006a0       _CheckLdrParamList         004016a0 f   rbxldr32.obj
 0001:000007b0       _LPL_FindFirst             004017b0 f   rbxldr32.obj
 0001:000007e0       _LDR_GetSysImgOffset       004017e0 f   rbxldr32.obj
 0001:000008c0       _BuildSystMemLayout        004018c0 f   rbxldr32.obj
 0001:00000b40       _IA32_BuildPageMap         00401b40 f   rbxldr32.obj
 0001:00000d60       _LoadCoreFile              00401d60 f   rbxldr32.obj
 
 entry point at        0001:00000000

这样mainCRTStartup又回到0x00401000处了,

继续开发我的操作系统吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值