您的位置:程序门 -> linux/unix社区 -> 内核及驱动程序研究区



关于汇编跳转到elf文件问题,忙了一个下午都弄不好,大家帮帮忙啊


[收藏此页] [打印本页]选择字色:背景色:字体:[][][]


关于汇编跳转到elf文件问题,忙了一个下午都弄不好,大家帮帮忙啊[已结贴,结贴人:nikshuang]
发表于:2007-10-17 22:04:04 楼主
代码如下,前面还有个引导程序,没有错误,这个程序在企图跳转到elf文件--kernel.bin,   即"jmp   0x08   :   0x30400"之前都没有出错,一到该跳转语句就出现错误,因为异常处理还没做好,所以不知道什么错误,而kernel.bin是一个打印单个字符的小程序,没有错误。
我编译kernel.bin用到的命令:   nasm   -f   elf   kernel.o   -o   kernel.asm,   ld   -s   -ttext   0x30400   -o   kernel.bin   kernel.o  

卡在这里一个下午了,郁闷啊,高手帮看看啊,   谢谢了   ~~~~~~~~

page_dir equ 0x100000           ;页表目录首地址
page0 equ 0x101000           ;页表0首地址
page1 equ 0x102000
page2 equ 0x103000
page3 equ 0x104000

begin:
mov ax,   cs
mov es,   ax
mov ds,   ax
mov ss,   ax
mov sp,   0x200

;打印提示信息
mov ah,   0x3
xor dh,   dh
int 0x10

mov cx,   29
mov ax,   msg
mov bp,   ax
mov ax,   0x1301
mov bx,   0x0007
int 0x10

;向bootsect一样,将自己移动到物理内存开始处,即0x00000
mov ax,   0x0000
mov es,   ax
xor di,   di
xor si,   si
mov cx,   256
rep
movsw

jmp 0x0000:   go

go:
mov ax,   cs
mov es,   ax
mov ds,   ax
mov ss,   ax
mov sp,   0x200

;进入保护模式
lgdt [gdt_48]

cli

in al,   0x92
or al,   0x02
out 0x92,   al

mov eax,   cr0
or eax,   1
mov cr0,   eax

jmp dword 0x08:   protect_mode

[section   .s32]
align   32
[bits   32]
;保护模式下运行
protect_mode:
mov ax,   0x18 ;显示段
mov gs,   ax
mov ax,   0x10 ;内核数据段
mov ds,   ax
mov es,   ax
mov ss,   ax
mov esp,   0x800 ;保护模式下的堆栈大小,   2k

;=================================================================
;   设置分页机制,   phoenix最大只支持16m的物理内存,所以只需要4个页表
;   每个页表有1024项,每项占4个字节
;=================================================================

do_setup_paging:
;将页表目录项指向各个页表,   pagex   +   7,其中7是页表参数指的是该页在用户态存在,可读写
mov edi,   page_dir
mov eax,   page0   +   7
mov ecx,   4
cld
do_page_dir_ptr:
stosd
add eax,   0x1000
loop do_page_dir_ptr

;将各个页表项指向每个物理内存页,   使用倒退填充的方法
mov edi,   page3   +   4092 ;最后一页表的最后一页表项
mov eax,   0xfff000   +   7 ;物理内存的最后一页
std
do_page_ptr:
stosd
sub eax,   0x1000
jge do_page_ptr

;设置cr3指向页表目录并打开分页机制
mov eax,   page_dir
mov cr3,   eax
mov eax,   cr0
or eax,   0x80000000
mov cr0,   eax
jmp ok
ok:
nop ;延迟

;判断0x30000位置是否已经读入elf格式kernel.bin
cmp byte   [0x30000],   0x7f
jne no_elf
cmp byte   [0x30001],   0x45
jne no_elf
cmp byte   [0x30002],   0x4c
jne no_elf
cmp byte   [0x30003],   0x46
jne no_elf
jmp elf
no_elf:     ;kernel.bin没有读入0x30000开始的物理内存地址
mov edi,   (80   *   10   +   10)   *   2
mov al,   'n'
mov ah,   0x0c
mov [gs:edi],   ax
jmp $
elf:
;=================================================================
;   将控制权交给kernel,   head结束
;=================================================================
mov edi,   (80   *   10   +   10)   *   2
mov al,   'y'
mov ah,   0x0c
mov [gs:edi],   ax
;jmp $

                ;跳转到kernel.bin,   0x30400是kernel.bin的入口
jmp 0x08   :   0x30400

msg: db "begin   into   protect   mode   ...",   13,   10

gdt_48:
dw 0x7ff
dd 0x10000   +   gdt

gdt:
dw 0,   0,   0,   0 ;第一项,空项

;代码段
dw 0xffff ;段限长,   0x800   -   1,   最多只能有256个描述符,而一个描述符占8个字节
dw 0x0000 ;段基址
dw 0x9a00 ;参数   +   段基址,   可执行/只读  
dw 0x00cf

;数据段  
dw 0xffff ;段限长,   0x800   -   1,   最多只能有256个描述符,而一个描述符占8个字节
dw 0x0000 ;段基址
dw 0x9200 ;可读刻写
dw 0x00cf

;显示段(用于内核调试)
dw 0xffff
dw 0x8000
dw 0x920b
dw 0x0000

times 252   *   8 db 0 ;填充剩余的描述符
发表于:2007-10-17 22:06:501楼 得分:0
。。。。。复制过来的时候程序格式还是好好,一帖到这里就没有缩进了,不好意思,大家帮帮我吧,悬赏100分。。。。
发表于:2007-10-17 22:13:382楼 得分:0
忘了说了,在这个程序的前面已经将kernel.bin文件读入到内存0x30000开始的地方,因为我设置它的入口为0x30400所以为方便起见就直接将其读入到0x30000开始的地方,后面判断0x30000是否有elf文件的方法是看其前4个字节是否依次是   7f   45   4c   46
发表于:2007-10-18 11:52:333楼 得分:0
是太长看不下去,还是.......
发表于:2007-10-18 12:00:314楼 得分:0
太长了...
发表于:2007-10-18 15:19:275楼 得分:0
我也遇到过类似的问题,经验是用bochs调试,在执行jmp   0x08   :   0x30400这一行上加断点,然后看0x30400的内存值是否是正确的。你贴的代码不完整,缺少段描述符的定义以及加载kernel.bin的部分,没办法帮你调试。我猜测,很可能是读取kernel.bin部分出的错,比如:只读了文件的一个数据块(512bytes)。
发表于:2007-10-18 16:45:356楼 得分:0
楼上的朋友,那要读入多少个扇区啊,我的kernel.asm很小的,只是打印一个字符而已,难道超过一个扇区??我读入的的确是一个扇区,如下:
global _start

_start:
mov edi,   (80   *   10   +   10)   *   2
mov al,   'p'
mov ah,   0x0c
mov [gs:edi],   ax
jmp $

描述符不是在这里定义了吗:

gdt_48:  
dw   0x7ff  
dd   0x10000   +   gdt  

gdt:  
dw   0,   0,   0,   0   ;第一项,空项  

;代码段  
dw   0xffff   ;段限长,   0x800   -   1,   最多只能有256个描述符,而一个描述符占8个字节  
dw   0x0000   ;段基址  
dw   0x9a00   ;参数   +   段基址,   可执行/只读    
dw   0x00cf  

;数据段    
dw   0xffff   ;段限长,   0x800   -   1,   最多只能有256个描述符,而一个描述符占8个字节  
dw   0x0000   ;段基址  
dw   0x9200   ;可读刻写  
dw   0x00cf  

;显示段(用于内核调试)  
dw   0xffff  
dw   0x8000  
dw   0x920b  
dw   0x0000  

times   252   *   8   db   0   ;填充剩余的描述符  
 
发表于:2007-10-18 17:20:127楼 得分:100
只读入一个块肯定是不对的。因为你把kernel链接成elf格式,就必然会超过512字节。查一查kernel.bin的大小就可知。如果只读一个块到0x30000,这个块结束的位置是0x301ff,之后的地址根本就没有写入。也就是说0x30400位置没有你需要的代码。
发表于:2007-10-18 17:26:268楼 得分:0
最后,给个建议:如果想写操作系统,学习bochs调试很重要。
发表于:2007-10-18 19:21:089楼 得分:0
amdahl大哥,你太有才,我怎么连这也没注意呢,看了kernel.bin的2进制代码,的确是x0510长,真的太感谢了你了。
还有bochs我会好好学的,谢谢了
发表于:2007-10-18 19:25:1610楼 得分:0
啊,一给分了这张帖就不置顶了,都不想给分了,啊哈哈哈,不知道你能不能看到我对你的感谢,你真的帮了我的大忙,谢谢了
发表于:2007-10-18 19:27:3411楼 得分:0
我看了代码,有几个问题需要注意:
1)你链接的时候把kernel.bin代码段放在0x30400     这个应该是线性地址。按照你的描述表和页表自己转换,看看是不是在你需要的物理内存地方。
2)保护模式启动没有?
3)你肯定知道自己的程序放在物理的是什么地方。根据你自己设置的gdt表和页表计算一下0x08   :   0x30400。虚地址-> 线性地址-> 物理地址。是不是正确。


快速检索

最新资讯
热门点击