免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7778 | 回复: 8
打印 上一主题 下一主题

elf to bin 问题请教 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-04-22 13:02 |只看该作者 |倒序浏览
我在LINUX下用AT&T的汇编写了一个BOOT程序,使用GAS和LD生成ELF文件格式
但我的在制作虚拟启动盘的时候(WINDOWS上)却需要.bin格式的文件,应该怎么做?

论坛徽章:
0
2 [报告]
发表于 2007-04-22 20:50 |只看该作者
原帖由 shineyear 于 2007-4-22 13:02 发表于 1楼  
我在LINUX下用AT&T的汇编写了一个BOOT程序,使用GAS和LD生成ELF文件格式
但我的在制作虚拟启动盘的时候(WINDOWS上)却需要.bin格式的文件,应该怎么做?


你用 gas 写 boot 程序

gas 并不适合用来写 boot 程序,据我所知 gas 不能编写 16 位代码

不知,你的 boot 程序是怎么写的,能否给大家看看

当然,通过某些技巧 gas 是可以生成 16 位代码,不过要熟悉指令格式

论坛徽章:
0
3 [报告]
发表于 2007-04-22 22:28 |只看该作者
在.text前面加上1句 .code16

论坛徽章:
0
4 [报告]
发表于 2007-04-22 22:39 |只看该作者
找到一个方法,还没有测试,先贴出来给大家参考
ld -o test -Ttext 0x0 -e main test.o
objcopy -R .note -R .comment -S -O binary test test.bin

论坛徽章:
0
5 [报告]
发表于 2007-05-17 10:24 |只看该作者
之前的做法有些出入,我把自己写的启动程序和编译方法写在BLOG里了,谁需要可以来看
http://www.pangfan.com/u/shineyear/archives/2007/83.html

论坛徽章:
0
6 [报告]
发表于 2007-05-18 19:53 |只看该作者
shineyear 兄弟,好好地整理一下,重新贴在版里,偶给你加个精华贴

论坛徽章:
0
7 [报告]
发表于 2007-05-21 12:32 |只看该作者
收到

自己动手写内核(第1课:引导程序)





目标:使"system"从软盘启动,并打印"Hello World!"

内存寻址

处理器以‘字节’管理和访问内存,每个字节都有独立的地址,即物理地址。有两种地址映射方式:分段和分页,skelix内核中都用到了。


段对于我们来说再熟悉不过了,先回顾一下dos时期的段吧。它是一个16位的寄存器,所以最多可以直接访问2^16字节的内存,即64K。这对应用程序来说太少了,于是Intel使用Segment:Offset结合方式来表示一个虚拟地址。段寄存器左移4位加上偏移就得到实际的物理地址了。例如,0x?>7c00:0x0189表示物理地址0x7c189,而不是0x7c000189。计算过程如下:


7C000
+ 0189
-------
7C189

现在我们来计算最大可以访问的地址:FFFF:FFFF

FFFF0
+ FFFF
-------
10FFEF

这个范围是1M + 65519 bytes, 因为在80386中使用了20位地址线,所以可以额外多访问65519个字节虚拟地址,例如地址0x100010被映射到地址0x10,访问这两个地址是等价的。

表示同一个物理地址有多种方式,例如07C0:0000和0000:7C00 就是一样的。


另一个概念是线性地址,这个是32位地址,只有当分页机制开启时才有效,文章后面会提到它。


引导过程


当系统上电或RESET时,处理器将执行一些列的初始化,寄存器被设置成非预知状态,并且cpu处于实模式。也许你想知道cpu是怎样设置segmentffset为物理地址FFFF0的(0xf000:0xfff0就是bios入口地址),这是因为cs寄存器有一个非可见部分,它保存了ffff:0000地址,并且cs在初始化时会被装入f000值。此后以正常方式使用它。当bois取得控制权后,根据用户配置(从软驱,硬盘,或cdrom)中读取第一个sector到00007C00,并跳转到该地址执行(就是引导程序bootstrap)。在bootstrap中我们可以使用bios中断,但是进入kernel后就不能再使用了。



程序一:使用as和ld的范例


你可以在下载源程序的


.text .text表示代码段
.globl start表示start可以用作外部符号
.code16 GCC默认使用32位地址和操作数,这里告诉它使用16位
start:
jmp start 死循环

.org 0x1fe, 0x90 .org NEW-LC, FILL,说明:这里填充0x90,是nop指令的机器码
.word 0xaa55


讲解:.org指令指示下一个数据地址,为了编译这个程序,我们写了一个Makefile,总不能老是敲命令吧,呵呵。

网络上可以找到很多写Makefile的资料,编译选项才是我们关注的焦点。



AS=as gcc汇编工具
LD=ld gcc连接器

.s.o:
${AS} -a $< -o $*.o >$*.map

all: final.img

final.img: bootsect
mv bootsect final.img

bootsect: bootsect.o
${LD} --oformat binary -N -e start -Ttext 0x7c00 -o bootsect $<


讲解:ld可以被配置为支持多于一种的目标文件. binary表示没有程序头和其他信息,仅仅是一些裸数据。如果没有这个选项,将被默认链接为elf格式。-N把text和data节设置为可读写。-Ttext将text节起始地址设置为0x7c00(在jmp和数据引用等重定位链接时会用到这个参考值),所有的引用地址都是在7c00这个地址上加出来的。-e选项指定程序入口点

现在我们运行make指令编译一下:

[root@root~/source/os/skelix/01/first.cry]$ ls
bootsect.s COPYING Makefile
[root@root~/source/os/skelix/01/first.cry]$ make
as -a bootsect.s -o bootsect.o >bootsect.map
ld --oformat binary -N -e start -Ttext 0x7c00 -o bootsect bootsect.o
mv bootsect final.img
[root@root~/source/os/skelix/01/first.cry]$ ls
bootsect.map bootsect.o bootsect.s COPYING final.img Makefile
[root@root~/source/os/skelix/01/first.cry]$


现在,我们启动vmware,运行,载入软驱映象文件"final.img",我们得到一个黑屏,这是正确的,因为我们什么也没有做。


程序一:显示 Hello World!

好了,上面的黑屏程序并不是太好玩,现在我们尝试在上面打印"Hello World!"

.text
.globl start
.code16
start:
jmp code
msg: 使用jmp指令跳过该变量,这是我们为什么在Makefile使用-N链接选项了
.string "Hello World!\x0"
code:
movw $0xb800,%ax
movw %ax, %es

0xb800是显存的开始地址。$表明其后是一个立即数。执行语句
ax寄存器的值就变为0xb800,这就是显存的地址。下面再将这个值移至es寄存 器,es是附加段寄存器。请记住8086有一个分段的体系结构。它的各段寄存器为代码段、数据段、堆栈段和附加段,对应的寄存器名称分别为cs、ds、ss和es。事实上,我们把显存地址送入了附加段,因此,任何送入附加段的东西都会被送到显存中。



xorw %ax, %ax
movw %ax, %ds

movw $msg, %si 为movsb指令设置正确的si和di
xorw %di, %di
cld
movb $0x07, %al 字的颜色

1:
cmp $0, (%si)
比较si指向的 地址内容和0
je 1f   
相同
跳转到下一个 1处
movsb
stosb
jmp 1b
1: jmp 1b
跳转到上一个 1处 死循环

.org 0x1fe, 0x90填充字符
.word 0xaa55以aa55为结尾

论坛徽章:
0
8 [报告]
发表于 2007-05-21 21:20 |只看该作者
shineyear 兄弟的论述有些不正确之处。

例如:
>> 处理器将执行一些列的初始化,寄存器被设置成非预知状态
每一个寄存器都是有初始值的。具体参看一看 Intel 或 AMD 文档,不是非预知状态


>> 0xf000:0xfff0就是bios入口地址
   BIOS 的入口地址正确来说是:FFFFFFF0。主板芯片组决定 BIOS 哪部分代码被映射到地址 FFFFFFF0。不同的 BIOS 可能不同部分被映射到 FFFFFFF0 去。
   BIOS被映射到 FFFFFFF0 地址是总是一条 jmp far 指令。这时候经过跳转后进入实模式。

>> 这是因为cs寄存器有一个非可见部分,它保存了ffff:0000地址,
    cs 的选择子是:F000, 基地址是:FFFF0000 等。 选择子是可见的,基地址等是不可见的。



不过 shineyear 兄弟动手能力还是挺强的。值得鼓励,再接再励。加精华了。

论坛徽章:
0
9 [报告]
发表于 2007-05-21 23:08 |只看该作者
多谢斑竹赐教,又学到知识了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP