实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制:memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_offset, p_filesz);复制可能不止一次,如果Program header ...
实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制:
memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_offset, p_filesz);
复制可能不止一次,如果Program header有n个,复制就进行n次。
每一个Program header都描述一个段,语句中的P_offset为段在文件中的偏移,p_filesz为段在文件中的长度,p_vaddr为段在内存中的虚拟地址。
由ld生成的可执行文件中p_vaddr的值总是一个类似于0x8048XXX的值,至少我们的例子中是一个这样的值。可是我们启动分页机制时地址都是对等映射的,内存地址0x8048XXX已经处在128MB内存以外(128MB的十六进制表示是0x8000000),如果计算机的内存小于128MB的话,这个地址显然已经超出了内存大小。
即便计算机有足够大的内存,显然,我们也不能让编译器来决定内核加载到什么地方。解决它有两个办法,一是通过修改页表让0x8048XXX映射到较低的地址,另一种方法就是通过修改ld的选项让它生成的可执行代码中p_vaddr的值变小。
nasm -f elf -o kernel.o kernel.asm
ld -m elf_i386 -s -Ttext 0x30400 -o kernel.bin kernel.o
程序的入口地址就变成0x30400了,ELF header等信息会位于0x30400之前。此时的ELF header和Program header table的情况如下表所示:
根据上表,我们应该这样放置内核:
memcpy(30000h, 90000h+0, 40Dh);
也就是说,我们应该把文件从开头开始40Dh字节的内容放到内存30000h处。由于程序的入口在30400h处,所以从这里就可以看出,实际上代码只有0Dh+1个字节。下面是Kernel.bin的内容:
上面被星号省去的部分都是0.从中可以看出,从400h到40Dh是仅有的代码,0xEBFE正是代码最后的“jmp $”。
下面的代码实现了将Kernel.bin根据ELF文件信息转移到正确的位置。它很简单,找出每个Program header,根据其信息进行内存复制:
; InitKernel ---------------------------------------------------------------------------------; 将 KERNEL.BIN 的内容经过整理对齐后放到新的位置; 遍历每一个 Program Header,根据 Program Header 中的信息来确定把什么放进内存,放到什么位置,以及放多少。; --------------------------------------------------------------------------------------------InitKernel: xor esi, esi mov cx, word [BaseOfKernelFilePhyAddr+2Ch];`. ecx <- pELFHdr->e_phnum movzx ecx, cx ;/ mov esi, [BaseOfKernelFilePhyAddr + 1Ch] ; esi <- pELFHdr->e_phoff add esi, BaseOfKernelFilePhyAddr;esi<-OffsetOfKernel+pELFHdr->e_phoff.Begin: mov eax, [esi + 0] cmp eax, 0 ; PT_NULL jz .NoAction push dword [esi + 010h] ;size ;`. mov eax, [esi + 04h] ; | add eax, BaseOfKernelFilePhyAddr; | memcpy((void*)(pPHdr->p_vaddr), push eax ;src ; | uchCode + pPHdr->p_offset, push dword [esi + 08h] ;dst ; | pPHdr->p_filesz; call MemCpy ; | add esp, 12 ;/.NoAction: add esi, 020h ; esi += pELFHdr->e_phentsize dec ecx jnz .Begin ret; InitKernel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
原标题:Linux内核系列—12.c.操作系统开发之从Loader进入内核 ●
关键词:linux
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:
admin#shaoqun.com
(#换成@)。