【汇编要笑着学】第一个程序 | bochs使用 | mov指令 | 运算指令add和sub

Ⅰ.编写第一个程序

直接抛出一段程序:

SECTION MBR vstart=0x7c00 ; 起始地址编译在0x7c00
    mov ax,cs             
    mov ds,ax             
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00   ; 上面这些都没什么用,但是都是必须的
                    ; 就把这些理解为初始化吧    

    mov ax, 0x6666

    jmp $

    times 510 - ($ - $$) db 0 
    db 0x55,0xaa

这段代码会点英文应该就看得出作用,具体的我就不讲了。

等下会具体解释。

实践是最好教学。

我们先来运行这段代码。

我们首先使用nasm来编译这段汇编。(没有安装的自行到上一篇进行安装)

nasm -o a.bin a.S

我这里把汇编保存在了a.S文件里。

输出了一个a.bin文件。

我们打开一下看看这个编译好的二进制文件。

很好,根本看不懂。

没事,我们数一数,可以发现不多不少,这个程序刚好512字节。

中间的部分用0填充。

times 510 - ($ - $$) db 0 

这一切都得益于上面这行代码。

这是因为bios会自动从硬盘的第一个扇区(一个扇区512字节)载入引导程序。

都是最后两个字节怎么是55AA

 这样bios就知道这是一个没有问题的扇区,不然就会。

我们再说说为什么程序的起始地址要设置位0x7c00

准确的说是0x7c000,因为这里的真实地址要偏移四位。

这个...

 

我也不知道,这个是intel工程师们写死的。

不这样的话...

不爽的自己去找intel的工程师,别找我。

接下来我们要怎么运行他,还用问?

去找bochs呀!

Ⅱ.bochs使用

0x00 创建硬盘

bochs是一个虚拟机程序,众所周知,电脑首先都需要一个硬盘和其他一系列东西才能运行。

其中bochs需要我们另外创建的这是硬盘文件。

我们可以使用bochs提供的工具bximage来创建一个硬盘。

这里自行配置环境变量。

打开终端输入命令

bximage

然后像下面一样选择:

这里我们把硬盘的大小设置为60MB,绰绰有余了。

0x01 创建配置文件

接下来我们要创建一个配置文件。

配置文件相当于定义bochs虚拟机的配置一样。

我们的配置文件如下:

megs : 512 #设置内存大小, 512M有点大材小用了

romimage: file=../bochs/BIOS-bochs-latest # 把这里替换成自己的路径
vgaromimage: file=../bochs/VGABIOS-lgpl-latest # 这里也是

boot: disk # 从硬盘启动

log: bochs.out

mouse:enabled=0
keyboard:keymap=../bochs/keymaps/x11-pc-us.map # 这里也是

ata0:enabled=1,ioaddr1=0x1f0,ioaddr2=0x3f0,irq=14
ata0-master: type=disk, path="hd60M.img", mode=flat,cylinders=121,heads=16,spt=63

#gdbstub:enabled=1,port=1234,text_base=0,data_base=0,bss_base=0

接下来我们使用bochs运行一下试试。

bochsdbg -f bochsrc

-f 知道配置文件名称。

bochsdbg是调试模式。

回车运行试试。

点击start运行!

输入c回车

 

额,我们好像还没载入汇编程序。

0x02 把程序写入硬盘 

我们接下来要把程序写入硬盘文件。

我这里使用的工具是git里的dd命令

命令如下:

dd if=a.bin of=hd60M.img bs=512 count=1 conv=notrunc

意思就是把a.bin复制到hd60M的以512字节为单位的第一个区域。

(⊙﹏⊙)

有点绕口

再次运行

输入c,等个几分钟(引导有点慢)

似乎还是没有效果。

哈哈,怎么可能呢?你在想什么?

我们输入ctrl+c,停止,输入r命令查看寄存器信息

 ax寄存器的值成功被我修改成了0x6666

Ⅲ.mov指令

皮了那么久,是时候讲点真东西了。

首先就是这里面很常见的mov指令。

0x00 mov指令是什么

mov指令其实就是一个苦逼的搬运工。

把数据从一个地方搬运到一个地方。

比如说:

mov ax, 0x66

相当于高级语言的(以python为例)

ax = 0x66

0x01 mov指令格式

mov指令格式如下:

mov 目标对象, 源对象

目标对象和源对象可以是寄存器,立即数也可以是内存里的地址。

0x02 例子

内容也很简单,我给出一个实例吧

mov ax, 0x666 # 把0x666复制到ax
mov bx, ax # 把ax的数据复制到bx
mov byte [gs:0x666], ax # 把ax的数据复制到内存里的[gs:0x666]的位置

Ⅳ.运算指令add和sub

cpu大哥最擅长的还是运算,汇编指令中也就肯定少不了计算的指令。

这节课就只介绍两个最基础的,加法和减法。

0x00 add加法指令

加法大家都会吧!

不会!

没事,跟我读: 1+1=2,1+2=3,1+3=4...

......

add加法指令的格式也十分简单。

add 目标对象, 源对象

这个操作会把目标对象与源对象相加,然后把结果存入目标对象中。

来吧!让我们试一试!

SECTION MBR vstart=0x7c00 ; 起始地址编译在0x7c00
    mov ax,cs             
    mov ds,ax             
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00   ; 上面这些都没什么用,但是都是必须的
                    ; 就把这些理解为初始化吧    

    mov ax, 0x66

    add ax, ax

    jmp $

    times 510 - ($ - $$) db 0 
    db 0x55,0xaa

代码很简单吧。

我们输入之前的一堆命令,编译试一试。

 可以看到ax的内容成功变成了0x66

那可不可以计算大一些的数呢

比如说把0x9999相加呢

我们把

mov ax, 0x66

改成

mov ax, 0x9999

我们再运行试试。

 

结果不应该是0x13332吗。

其实这就是发生了溢出。

因为ax寄存器只有16位,不够存储。

当然,也是有解决办法的。

很简单。

我们可以使用32位cpu里的eax寄存器。eax可以理解成两个ax寄存器拼在一起。

我们只需要把里面的ax改成eax就行了。

舒服了。

0x01 sub指令

sub指令的语法和add类似。

sub 目标对象, 源对象

作用就是把目标对象减去源对象,把结果存入目标对象中。

我就不多讲了。

给出一段代码和效果

SECTION MBR vstart=0x7c00 ; 起始地址编译在0x7c00
    mov ax,cs             
    mov ds,ax             
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00   ; 上面这些都没什么用,但是都是必须的
                    ; 就把这些理解为初始化吧    

    mov ax, 0x66
    sub ax, ax

    jmp $

    times 510 - ($ - $$) db 0 
    db 0x55,0xaa

0x00,没有问题。

 

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值