自制简单U盘引导程序
0基础如何编写并运行一个汇编程序 ?
这里涉及到两个概念:汇编器和链接器
汇编器(assembler)的作用是将用汇编语言编写的源程序转换成二进制形式的目标代码。Linux 平台的标准汇编器是 GAS,它是 GCC所依赖的后台汇编工具,通常包含在 binutils 软件包中。GAS 使用标准的 AT&T 汇编语法,可以用来汇编用 AT&T格式编写的程序:
由汇编器产生的目标代码是不能直接在计算机上运行的,它必须经过链接器的处理才能生成可执行代码。链接器通常用来将多个目标代码连接成一个可执行代码,这样可以先将整个程序分成几个模块来单独开发,然后才将它们组合(链接)成一个应用程序。Linux 使用 ld 作为标准的链接程序,它同样也包含在 binutils 软件包中。汇编程序在成功通过 GAS 或 NASM 的编译并生成目标代码后,就可以使用 ld 将其链接成可执行程序了:
准备工作:安装gcc,as86,ld86
gcc用于编译.c的程序,该程序用于将数据写入到U盘;
as86和ld86用于汇编和链接intel汇编语法下的汇编程序,该程序会写入数据到计算机的显示缓冲区,计算机会立即显示缓冲区的内容。
安装方法:
sudo apt-get install gcc bin86
编写并运行一个汇编程序步骤:
- 1.
vim hello.s
创建一个.s的文件 - 2.编写hello.s 的内容
- 3.编译:
as -o hello.o hello.s
- 4.链接:
ld -s -o hello hello.o
- 5.执行:
./hello
这里给出一在这里插入代码片
个简单程序hello world的汇编源代码:
#hello.s
.data
msg : .string "Hello, world!\\n"
len = . - msg
.text
.global _start
_start:
movl $len, %edx
movl $msg, %ecx
movl $1, %ebx
movl $4, %eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
题目描述
- 1、用汇编语言编写一小段程序,如在屏幕上输出一个字符。(调用中断)
- 2、利用命令或winhex等工具将编译好的二进制程序写入U盘的主引导记录
- 3、开机,选择U盘启动,观察实验效果。
- 4、进一步地,丰富前述程序的功能,如增加键盘中断,可以对键盘上的动作进行响应(如敲入某字符X,屏幕能回显即可)。
- 5、再次写入引导扇区,观察实验效果
下面是题目需要用到的一个小程序,屏幕输出按下的键盘:
NAME TURN
DSEG SEGMENT
A DB 'PLEASE INPUT (a~z):','$'
B DB 0AH,0DH,'$'
DSEG ENDS
SSEG SEGMENT STACK
DB 90H DUP(?)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG,SS:SSEG
START:
MOV AX,DSEG
MOV DS,AX
MOV DX,OFFSET A///提示输入
MOV AH,09H
INT 21H
MOV AH,01H
INT 21H
MOV BL,AL
SUB BL,20H///转换
MOV DX,OFFSET B
MOV AH,09H
INT 21H
MOV DL,BL
MOV AH,02
INT 21H//输出
MOV AH,4CH
INT 21H/结束
CSEG ENDS
END START
步骤
编写能够在屏幕显示字符的汇编程序
vim bootsetc.s
entry start
start:
mov ax,#0xb800
mov ds,ax
mov byte[0],#0x4c
mov byte[1],#0x1f
hlt
执行命令
as86 -o bootsect.o bootsect.s
ld86 -o bootsect bootsect.o
生成可执行文件bootsect。
编写可将数据写入U盘启动扇区的程序
vim write-mbr.c
#include <fcntl.h>
#include <stdio.h>
int main(int argc,char*argv[]){
int dev_flag,file_flag;
unsigned char buffer[512];
file_flag = open("./bootsect",O_RDONLY);
if(file_flag == -1){
perror("failed to read file boot");
return -1;
}
read(file_flag,buffer,510);
close(file_flag);
buffer[510] =0x55;
buffer[511] =0xaa;
dev_flag = open("/dev/sda",O_RDWR);
if(dev_flag == -1){
perror("failed to open device /dev/sda");
return -1;
}
write(dev_flag,buffer,512);
close(dev_flag);
puts("successful.");
return 0;
}
执行命令
gcc -o write-mbr write-mbr.c
将U盘接入电脑,挂载到linux上
首先用命令 sudo fdisk -l
可以通过容量找到对应U盘的设备名称。
然后用命令 sudo mount /dev/sda /mnt/flash
将U盘挂载到flash,注意该命令需要flash目录存在,不存在则要创建:
cd /mnt && sudo mkdir flash
。
最后执行 ./write-mbr
,shell返回successful,说明写入成功。
卸载设备,将U盘插入一台电脑,并通过BIOS将启动项改为U盘优先。开机便可一看到一个蓝底白色的L字符。
注意
1)U盘在第二次插回linux主机时,会出现挂载失败的现象,原因可能是由于写入了512个字节的数据破坏了U盘关于分区,文件系统信息的记录,因此目前的解决办法就是重新格式化U盘,命令为 mkfs.vfat /dev/sda。格式化完成后挂载成功,即可在此写入程序。
2)每次都需要重新格式化U盘,然后挂载U盘,编译好几个文件,因此考虑写一个shell脚本一次性完成数据的写入任务。