程序的加载和执行(六)——《x86汇编语言:从实模式到保护模式》读书笔记26


通过本文能学到什么?

  • NASM的条件汇编
  • 用NASM编译的时候,通过命令行选项定义宏
  • Makefile的条件语句
  • 在make命令行中覆盖Makefile中的变量值
  • 第13章习题解答
  • 复习如何构造栈段描述符

我们接着上篇博文说。
在我修改后的文件中,用到了条件汇编。
比如:

%ifdef DEBUGput_core_salt:  ;打印内核的符号... ...put_usr_salt:  ;打印用户的符号......
%endif

下文对此进行讲解。

1.条件汇编

与C预处理器相似,NASM允许对一段源代码只在某特定条件满足时进行汇编。
注意,C语言的预处理指令是由#字符开头的一些命令,NASM编译器的预处理指令由%开头。

1.1 只在某特定条件满足时进行汇编

%if<condition>;if <condition>满足时接下来的代码被汇编。......%elif<condition2>; 当 if<condition>不满足,而<condition2>满足时,该段代码被汇编。......%else;当<condition>跟<condition2>都不满足时,该段代码被汇编。......%endif

%else%elif子句都是可选的,也可以使用多于一个的%elif子句。

1.2 测试单行宏是否存在

%ifdef DEBUG...%endif

如果我们定义了宏DEBUG,那么省略号处的代码就会被汇编,否则不会。

以定义宏DEBUG为例,可以用两种方法。

1.3 在代码中直接定义宏

%define DEBUG

1.4 通过命令行选项

编译文件的时候,用-d 宏名称

    -d DEBUG

例如:

 nasm c13_core.asm -o c13_core.bin -d DEBUG

注意:-d可以写成-D,它和后面宏名之间的空格也可以不要。
例如:

 nasm c13_core.asm -o c13_core.bin -dDEBUG

2.关于Makefile

因为加入了条件汇编,所以Makefile和上篇博文中的不太一样。
上篇博文地址:
程序的加载和执行(五)——《x86汇编语言:从实模式到保护模式》读书笔记25

修改后的Makefile如下。

DEBUG = 0BIN = c13_mbr.bin c13_core.bin c13.bin empty
A_DIR = /home/cjy/a.img
C_DIR = /home/cjy/c.imgall:$(BIN).PHONY:all cleanc13_mbr.bin:c13_mbr.asmnasm $< -o $@dd if=$@ of=$(A_DIR)c13_core.bin:c13_core.asm
ifeq ($(DEBUG),1)nasm $< -o $@ -D DEBUG
elsenasm $< -o $@
endifdd if=$@ of=$(C_DIR) bs=512 seek=1 conv=notruncc13.bin:c13.asmnasm $< -o $@dd if=$@ of=$(C_DIR) bs=512 seek=50 conv=notruncempty:diskdata.txtdd if=$< of=$(C_DIR) bs=512 seek=100 conv=notrunctouch $@clean:$(RM) $(BIN)

2.1 条件语句

首先,我们定义了一个变量(也被称作宏)DEBUG,并给其赋值为0;
需要注意的是以下几行:

ifeq ($(DEBUG),1)nasm $< -o $@ -D DEBUG
elsenasm $< -o $@
endif

这里用到了Makefile的条件语句。执行make时,会根据运行时的不同情况选择不同的执行分支。
在这个例子中,当变量DEBUG的值为1时,就执行nasm $< -o $@ -D DEBUG
当变量DEBUG的值不为1时,就执行nasm $< -o $@

当我们想编译带调试信息的源文件,修改Makefile中DEBUG的值为1就可以了。

但是,还有没有更简单的方法呢?

2.2 在命令行中定义变量

当命令行中的变量(宏)定义跟makefile中的定义有冲突时,以命令行中的定义为准。所以,我们可以在执行make的时候加上变量=新值,以覆盖Makefile文件中的变量值。

对于本文的例子,除了修改Makefile中DEBUG的值为1这种方法外,还有一种方法是在命令行中重新给变量(宏)赋值。

make "DEBUG=1"

注意:当没有空格的时候,引号也可以省略。由于宏定义必须作为单个参数进行传递,所以要避免使用空格,所以更妥当的方法是使用引号。

3.第13章习题解答

在本章中,用户程序只给出建议的栈大小,但并不提供栈空间。现在,修改内核程序和用户程序,改由用户程序自行提供栈空间。要求:栈段必须定义在用户程序头部之后。

在这里,我给出自己的答案,供学习者参考。

3.1 对于源文件c13.asm的修改

修改有两处。第一处是:


由于栈空间由用户程序提供,所以必须指明栈段的汇编地址和大小,这样内核程序才能有足够的信息为用户创建栈段描述符。

第二处是:

因为题目已经要求栈段必须定义在用户程序头部之后,所以这里紧接着头部定义栈空间。

小插曲
编译这个文件,会报错。

c13.asm:14: error: division operator may only be applied to scalar values
make: *** [c13.bin] 错误 1

哦,这是为什么呢?我改成了

stack_len        dd (stack_end-0)/(4*1024) 

依然报同样的错误。
通过查资料,发现有的朋友是这样回答的:

A label is a relocatable value——its value is modified by the linker/loader.The difference between two labels(in the same section) is a scalar value, and NASM will work with it.

好吧,既然同一个section的两个标号的差值是标量,那我这样写好了:

 stack_len        dd (stack_end-stack_start)/(4*1024)  

其实stack_start这个标号之前是没有的,是我为了做差值专门加上的。
你还别说,这样写真的管用,不报错了。

3.2 对源文件c13_core.asm的修改

左边的代码(配书代码),内核为用户栈分配内存,然后计算栈的高端物理地址。
右边的代码(习题代码),内核不需要分配内存,仅仅从头部取出栈的起始地址,然后计算栈的高端物理地址。
这段代码是我半年前写的,可是现在读起来也觉得陌生了。那就解释一下最关键的3行,加深自己的记忆。

469      mov edx,edi
470      add edx,[edi+0x08]                ; 栈段起始的线性地址
471      add eax,edx                       ; 得到栈的高端物理地址 

此时,DS指向了0-4GB的数据段,EDI中的内容是用户程序的加载地址。
469:EDX中是用户程序的加载地址;
470:从用户头部偏移0x08处取得section.stack.start,加上用户程序的加载地址(EDX),就得到了用户栈的起始地址。如图所示。
471:栈段描述符中的基地址,应该是栈空间的高端物理地址,所以还要加上栈的大小(在EAX中)。
如果不明白为什么这样构造栈段描述符,可以参考我的博文:
如何构造栈段描述符

3.3 在Bochs中验证程序

我们的修改对吗?“实践出真知”。

3.3.1 验证思路

因为栈空间是用户程序提供的,内核只是根据头部信息创建对应的栈段描述符。所以我们要验证的就是栈段描述符和用户定义的栈是否相符。在上面提到的博文中,我已经详细推导了如何构造栈段描述符。

用户程序的头部结构如下图所示:

本实验的用户程序的符号表有3个符号,所以头部总长度为0x328;由于用户程序的加载地址是0x100000,所以栈空间的起始地址为0x100328;又因为栈空间大小定义为0x1000(4KB),所以栈空间的高端物理地址为0x100328+0x1000=0x101328
这应该就是栈段描述符的基地址。

有效段界限应为0xFFFFFFFF-栈的大小(以字节为单位),即0xFFFFFFFF-0x1000=0xFFFFEFFF,这应该是栈段描述符中的段界限。

3.3.2 验证结果

在Bochs中运行程序,跑起来后,Ctrl+C暂停程序,输入info gdt可以查看GTD的信息。我们看到在下图中:

黄色划线的描述符与我们的推理相符。所以,我们的修改是正确的。

【end】

程序的加载和执行(六)——《x86汇编语言:从实模式到保护模式》读书笔记26相关推荐

  1. 程序的加载和执行(五)——《x86汇编语言:从实模式到保护模式》读书笔记25

    程序的加载和执行(五)--<x86汇编语言:从实模式到保护模式>读书笔记25 前面几篇博文终于把代码分析完了.这篇就来说说代码的编译.运行和调试. 1.代码的编译及写入镜像文件 之前我们都 ...

  2. 程序的加载和执行(四)——《x86汇编语言:从实模式到保护模式》读书笔记24

    程序的加载和执行(四)--<x86汇编语言:从实模式到保护模式>读书笔记24 通过本文能学到什么? 怎样跳转到用户程序 用户程序通过调用内核过程完成自己的功能 怎样从用户程序返回到内核 接 ...

  3. 程序的加载和执行(一)——《x86汇编语言:从实模式到保护模式》读书笔记21

    程序的加载和执行(一) 本文及之后的几篇博文是原书第13章的学习笔记. 本章主要是学习一个例子,对应的代码分为3个文件: ;代码清单13-1;文件名:c13_mbr.asm;文件说明:硬盘主引导扇区代 ...

  4. 程序的加载和执行(三)——《x86汇编语言:从实模式到保护模式》读书笔记23

    程序的加载和执行(三)--读书笔记23 接着上次的内容说. 关于过程load_relocate_program的讲解还没有完,还差创建栈段描述符和重定位符号表. 1.分配栈空间与创建栈段描述符 462 ...

  5. html 执行外部js的函数,javascript – Chrome扩展程序:加载并执行外部脚本

    我无法在我的chrome扩展程序中加载和执行外部js-script.看起来和 this question一样,但我仍然无法弄清楚为什么它在我的情况下不起作用. 我的想法是,我希望在我的内容脚本中有一些 ...

  6. 小程序动画加载只执行一次的问题

    问题 最近, 想做个小程序的圆盘抽奖出来, 想要实现的效果是点击一次就旋转一次. 不过每次只有第一次点击有效, 再次点击就没有任何动画效果. 代码如下 rotate: function() {// 创 ...

  7. 任务和特权级保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记27

    本文及后面的几篇文章是原书第14章的读书笔记. 1.LDT(局部描述符表) 在之前的学习中,不管是内核程序还是用户程序,我们都是把段描述符放在GDT中.但是,为了有效实施任务间的隔离,处理器建议每个任 ...

  8. X86汇编语言从实模式到保护模式13:保护模式程序的动态加载和执行

    目录 1. 引入保护模式对程序加载与执行的影响 1.1 对应用程序的影响 1.2 对操作系统的影响 1.3 本章程序总体结构 2. MBR加载内核过程分析 2.1 内核头部段分析 2.1.1 内核总长 ...

  9. Java的加载与执行原理详解 Java程序从编写到最终运行经历了哪些过程

    前言 Java程序从编写到最终运行大概可概括为3个阶段:编写.编译.运行阶段. 一.编写阶段 程序员在硬盘某个位置新建一个xxx.java文件 使用记事本或者其他文本编辑器例如EditPlus打开xx ...

最新文章

  1. 2009全国公共英语五级(PETS-5)考试大纲概述
  2. python变量类型-python 变量类型 number
  3. python大杀器之requests安装
  4. 微型计算机接口技术常见问题,《微型计算机接口技术及应用》期末考试试卷及问题详解(64页)-原创力文档...
  5. 导致自然语言理解的困难的主要因素是什么?
  6. 14.图像透视——人类视觉,平行线测验,其他模型,乐趣与角度_4
  7. ThinkPHP3.2 常量参考
  8. nettry 入站事件如何传递到下一个handler
  9. Java注解的作用?
  10. 用递归的方式处理数组 把递归方法方法定义到数组的原型上 (这是一次脑洞大开的神奇尝试)...
  11. VI/VIM常用命令
  12. 完整的【ArcGIS地理信息系统空间分析实验教程】(包括光盘数据)
  13. PS打开PSD文档服务器未响应,ps打不开psd文件的解决方法
  14. Delphi POS打印的处理
  15. Caffe框架-入门浅谈及碰到的坑
  16. 试用期不合格通知单可以签吗?
  17. linux 使用shell/python编写钉钉自动监控报警脚本
  18. python multiprocessing dummy Pool 使用
  19. C++ 使用Poco库实现XML的读取和写入
  20. 蓝牙4.0 For IOS

热门文章

  1. JSP简单练习-一个简单的计数器
  2. Django模型层(models.py)之多表操作
  3. C语言 指针在函数传参中的使用
  4. bootstrap全局css样式
  5. C++ code:数值计算之矩形法求解积分问题
  6. npm和node.js升级
  7. 各类最新Asp .Net Core 项目和示例源码
  8. [leetcode] Restore IP Addresses
  9. Matlab cell矩阵处理
  10. 统计学:回归分析(2)