山东大学操作系统学习笔记:第3.1讲程序的结构-简单的程序

news2024/10/1 18:22:32

第3.1讲:程序的结构-简单的程序

可执行文件 & 程序的装入

image-20240918151520355

  • .rwdata(读写数据段): 存放程序中的含初值常量。这些常量在程序运行可以修改。

  • 零初始化数据段(.zidata/.bss - Block Started by Symbol):存放程序中的不含初值(初始化为0的)可修改常量。

  • 堆段: 存放程序的堆,也即动态分配内存时内存的来源。

  • 栈段: 存放程序的运行栈,以供过程调用时保存和恢复上下文。

可执行文件头

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


最后,在将控制权交给程序时,将PC指向.text段,将SP指向.stack段。


编译器、汇编器、链接器、调试器与解释器程序

image-20240918151901715

工具链

image-20240923192533286

外部符号引用

在一个目标文件中可能引用了其它目标文件的内容。由于编译 器一次生成一个目标文件,因此并不知道那些引用的内容的地 址在哪。况且,自身在内存中的位置也还没确定,因此所有对 符号的引用(全局变量访问、函数调用等等)的具体地址都只 能推迟。

这个时候需要链接器进行操作:链接器会先收集全部目标文件的符号,然后给每个符号分配地址。在地址确定后,反过来补全程序中对这些符号地址的引用。

image-20240923194210240

  • 直接回填法

image-20240918152955321

  • 间接地址法

image-20240918153038187


调用者向被调用者传递一个或多个参数

参数的传递有三种方法:

(1)通过全局变量传递(需要在数据段声明)

(2)通过栈传递(记得设置SP和SS)

(3)通过寄存器传递(寄存器数量有限)

下面是利用栈传递的情况:

image-20240923222447116

GPT解释:

这张图展示了两个 C 语言函数和它们对应的汇编代码,并且结合了栈帧的概念。我们分别解释一下左侧的 main 函数和右侧的 subp 函数及它们的汇编指令。

左侧代码:main 函数及其汇编指令

C 代码:
int main(void) {
    ...
    val = subp();
    ...
}
汇编指令解释:
  1. MOV BP, SP:保存栈指针到基址指针 BP。栈帧基址设置为当前栈顶指针(SP)。在函数调用中,BP 通常用于引用局部变量和参数。

  2. SUB SP, 2:在栈上分配 2 个字节的空间,可能是给局部变量 val 分配的空间。

  3. CALL FAR PTR SUBP:调用远程子程序 subp()。调用指令会将 IPCS(指令指针和代码段寄存器)压入栈中,然后跳转到 subp 函数的地址。

  4. MOV AX, [BP-2]:从栈中取出 subp 函数返回的值,BP-2 指向栈中的返回值,将其加载到寄存器 AX

  5. MOV VAL, AX:将 AX 中的值(subp 返回的值)存储到变量 VAL 中(对应 C 代码中的 val)。

  6. MOV SP, BP:将栈指针恢复到基址指针 BP 的值,清理栈帧。

右侧代码:subp 函数及其汇编指令

C 代码:
short subp(void) {
    ...
    return value;
}
汇编指令解释:
  1. MOV DX, VALUE:将 VALUE 的值(subp 函数要返回的值)移动到寄存器 DX

  2. MOV [BP-2], DX:将寄存器 DX 中的值存储到栈中 BP-2 的位置,这是给 main 函数的返回值留出的栈空间。

  3. RETF:返回远程调用,将 IPCS 出栈并恢复程序的执行,返回到 main 函数中。


栈帧分析:

  • main 函数调用 subp 时,栈中会保存当前的指令指针 (IP) 和代码段 (CS),从而实现函数调用的跳转。
  • subp 函数会将返回值放到栈中,main 函数再从栈中读取返回值并赋给 val
  • 栈指针 (SP) 和基址指针 (BP) 的配合用于管理函数调用时的参数传递和局部变量。

总体上,这段代码展示了如何通过栈来处理函数调用和返回值。


补充知识:

MOV指令,能实现以下操作:

  • CPU内部寄存器之间数据的任意传送(除了码段寄存器CS和指令指针IP以外)。

  • 立即数传送至CPU内部的通用寄存器组(即AX、BX、CX、DX、BP、SP、SI、DI),给这些寄存器赋初值。

  • CPU内部寄存器(除了CS和IP以外)与存储器(所有寻址方式)之间的数据传送,可以实现一个字节或一个字的传送。

  • 能实现用立即数给存储单元赋初值。

img

在汇编语言中,bp和sp分别指代以下内容:

  • sp(栈顶指针):指向栈顶地址,与SS相配合使用,用于访问栈中的数据。
  • bp(基址指针):指向栈帧的底部,一般称之为栈底指针,用于定位物理地址
    • BP叫做栈框指针,因为通过它就能找到与该过程相关的整个调用栈。调用栈包括参数,临时变量,还有返回时的IP

栈的四种类型

image-20240923222802997

递增栈的优势:便于判断栈是否溢出


Q:参数和返回值的传递都有多种方法。那么,调用一个函数时, 具体采取哪种方法,以及那种方法具体是怎样实现的?

A:被调用者和调用者都遵守的变量和返回值的传递规则。具体怎 样约定,是随心所欲的。但是,一旦这个标准确定下来,就必 须在整个项目中遵循,否则就会乱套。常见的8086(包括后续 的i686扩展)使用的传值约定大体如下。

image-20240923222955147


Q:为什么绝大多数调用约定都把参数放在栈上?为什么不使用寄 存器传递所有的参数,或者使用变量传递所有的参数呢?

A:栈的大小比较大,因此传递的参数可以比较多,准确地讲数量 是不受限制的。此外,栈传递参数非常好理解,一般是把当前SP 赋给BP,然后将参数列表从右往左依次入栈就可以了。被调用 者通过BP指针就可以寻址各个参数,调用完成后要将SP指针恢 复到原状也只需要将BP再赋给SP,非常方便。之所以8086的BP 寄存器被指定隐含SS段寄存器,就是为了方便栈传参。


Q:使用栈传递参数太麻烦了,要保存栈框,还要恢复栈指针。那 么,在小型程序中,能否在数据段定义几个变量传递参数呢?

A:(概括一下)这样的话不能使用任何形式的递归调用

Q:直接传参法和间接地址法的优劣比较(课前小测)

A:两者都是对于程序中符号地址的引用进行补全(链接器的操作)

  • 直接传参法:运行时速度快,但是不便于在运行时修改地址
  • 间接地址法:运行时速度满(相当于多进行一次指针转换),但是便于修改地址

寄存器保护约定

  • 调用者负责

  • 被调用者负责:更容易做到权责一致,但是会产生不必要的PUSH和POP

  • 混合制负责:部分寄存器由调用者负责保存,另一部分寄存器则由被调用者 负责保存。下例中,AX、BX由调用者负责保存,CX、DX则由被 调用者负责保存,且AX~DX中均含有调用者的有效数据。

    • 优势:一方面有利于生成尽量少的PUSH和POP,减少代码量,并方便被 调用者内部决定保护哪些寄存器(若被调用者也不使用那个寄存器,则不管便可),另一方面也允许在每次调用时定制保护列表,触碰尽量少的寄存器。
      • 一方面允许编译器进行高度复杂的优化,另一方面也方便人手写汇编。

栈框恢复约定:

  • 调用者负责
    • 优势:可以最少化栈框调整。如果一个过程被连续调用两次,或者在 循环中被反复调用,或者尾递归,那么也许调整一次SP就足够了, 已分配的栈框本身可以重新填值并复用。另外,栈框怎么调整 是调用者说了算,因此调用者可以更灵活地处理每一次调用。 这在那些**可变参数函数(如C语言printf)**中非常有用。
  • 被调用者负责
  • 混合制负责
调用者负责:

image-20240924203823744

这段栈框恢复代码的作用是保存和恢复调用子程序时的栈帧。下面是对每行代码的逐步解释:

  1. PUSH BP:将基指针(BP)的值压入栈中。这样做的目的是保护当前栈框,以便在函数返回时能够恢复。

  2. MOV BP, SP:将当前栈指针(SP)的值赋给基指针(BP)。这一步建立了新的栈帧,使得接下来的局部变量和参数可以通过BP来访问。

  3. PUSH VAR:将局部变量(这里用VAR表示)压入栈中,通常用于为子程序传递参数或保存局部变量。

  4. CALL SUBP:调用名为SUBP的子程序。在调用时,返回地址会自动压入栈中,以便子程序执行完毕后能够返回到正确的位置。

  5. MOV SP, BP:在子程序执行完毕后,这一行将栈指针(SP)恢复到基指针(BP)的位置。这意味着局部变量和参数已经不再需要,可以将栈指针恢复到上一个栈框的状态

  6. POP BP:从栈中弹出之前保存的BP值,恢复到原来的基指针。这一步是栈框恢复的最后一步,确保在函数返回后能够正确地访问调用者的栈框。

总结来说,这段代码通过保存和恢复BP值以及SP值来管理栈帧,使得在调用子程序时能够正确处理局部变量和参数,并在返回时恢复到原来的栈状态。

被调用者负责:

image-20240924204929515

这段代码展示了被调用者负责的栈框恢复约定,主要分为主函数和子程序两部分。以下是对代码的详细解释:

主函数部分

  1. PUSH BP:将当前基指针(BP)压入栈,以保护调用者的栈框。

  2. MOV BP, SP:将当前栈指针(SP)的值赋给基指针(BP),建立新的栈框。

  3. PUSH VAR1:将参数(VAR1)压入栈中,以便传递给子程序SUBP。

  4. SUB SP, 2:在栈中为局部变量分配空间,这里分配了2个字节。

  5. CALL SUBP:调用子程序SUBP,返回地址会被压入栈。

  6. POP BP:从栈中弹出之前保存的BP值,恢复调用者的栈框。

子程序部分 (SUBP)

  1. 注释:指出被调用者需要弹出所有局部变量和参数。此处有两个参数和一个局部变量需要弹出。

  2. MOV AX, [BP-2]:通过基指针(BP)访问压入栈中的第一个参数(VAR1)。因为参数相对于BP的位置是负偏移。

  3. MOV [BP-4], CX:将寄存器CX的值存储到第二个局部变量的位置(BP-4)。这说明此子程序有一个局部变量。

  4. RET 4:从子程序返回,同时清理4个字节的栈空间,实际上是弹出之前传递的参数。此指令确保在返回时,栈指针恢复到调用子程序之前的状态。

总结

这段代码体现了被调用者负责的栈框恢复约定:在子程序中,必须处理自己的局部变量和参数,并在返回时清理栈空间,以保证栈的完整性。主函数负责设置栈框和调用子程序,而子程序则负责自己的栈管理。

序言,尾声

image-20240924165538888

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2182897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《自控原理》最小相位系统

在复平面右半平面既没有零点,也没有极点的系统,称为最小相位系统,其余均为非最小相位系统。 从知乎看了一篇答案: https://www.zhihu.com/question/24163919 证明过程大概率比较难,我翻了两本自控的教材,…

【中间件】fastDFS的相关知识

一、分布式文件系统 1.1 传统的文件系统 我们在Linux中学习的文件系统就是传统的文件系统: 传统的文件系统格式: ntfs/fat32/ext3/ext4 可以被挂载和卸载,就是一般一个盘可以分成多个盘,每一盘都可以挂载到不同的目录路径中。…

实时语音交互,打造更加智能便捷的应用

随着人工智能和自然语言处理技术的进步,用户对智能化和便捷化应用的需求不断增加。语音交互技术以其直观的语音指令,革新了传统的手动输入方式,简化了用户操作,让应用变得更加易用和高效。 通过语音交互,用户可以在不…

考研笔记之操作系统(三)- 存储管理

操作系统(三)- 存储管理 1. 内存的基础知识1.1 存储单元与内存地址1.2 按字节编址和按字编址1.3 指令1.4 物理地址和逻辑地址1.5 从写程序到程序运行1.6 链接1.6.1 静态链接1.6.2 装入时动态链接1.6.3 运行时动态链接 1.7 装入1.7.1 概念1.7.2 绝对装入1…

算法-汉诺塔问题(Hanoi tower)

介绍 汉诺塔是源于印度的一个古老传说的小游戏,简单来说就是有三根柱子,开始的时候,第一根柱子上圆盘由大到小,自下往上排列。这个小游戏要实现的目的呢,就是要把第一根柱子上的圆盘移到第三根的柱子上去;…

【重学 MySQL】四十四、相关子查询

【重学 MySQL】四十四、相关子查询 相关子查询执行流程示例使用相关子查询进行过滤使用相关子查询进行存在性检查使用相关子查询进行计算 在 select,from,where,having,order by 中使用相关子查询举例SELECT 子句中使用相关子查询…

带你0到1之QT编程:二十二、QChart类图表及折线图、直方图、饼图的三大可视化图表实战!

此为QT编程的第二十二谈!关注我,带你快速学习QT编程的学习路线! 每一篇的技术点都是很很重要!很重要!很重要!但不冗余! 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点!…

09_OpenCV彩色图片直方图

import cv2 import numpy as np import matplotlib.pyplot as plt %matplotlib inlineimg cv2.imread(computer.jpeg, 1) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) plt.show()plot绘制直方图 plt.hist(img.ravel(), 256) #ravel() 二维降一维 256灰度级…

【JavaEE】http/https 超级详解

🔥个人主页: 中草药 🔥专栏:【Java】登神长阶 史诗般的Java成神之路 🦊一.定义 HTTP(HyperText Transfer Protocol)即超文本传输协议,他是应用非常广泛的应用层协议,是…

《PMI-PBA认证与商业分析实战精析》 第3章 需要评估

本章涵盖的考试重点: 需要评估的四项活动 需要评估四项活动的可交付成果 需要评估相关活动的技术 商业论证的内容 情境说明书的格式 目的、目标和商业论证的层次结构 成本收益分析的四种财务计价方法 需要评估领域就是聚焦在目标定义上。 商业分析师所需要…

ZenStack全栈开发工具(一)快速使用指南

简介 ZenStack是一个TypeScript工具,通过灵活的授权和自动生成的类型安全的 API/钩子来增强 Prisma ORM,从而简化全栈开发 数据库-》应用接口 数据库-》前端 参考官方网站:https://zenstack.dev/ 如果我们想做一个全栈开发的web应用程序&am…

目标检测技术的发展:从R-CNN、YOLO到DETR、DINO

“深度人工智能”是成都深度智谷科技旗下的人工智能教育机构订阅号,主要分享人工智能的基础知识、技术发展、学习经验等。此外,订阅号还为大家提供了人工智能的培训学习服务和人工智能证书的报考服务,欢迎大家前来咨询,实现自己的…

[FlareOn3]Challenge11

载入PE. 32 bit,无壳. 载入IDA(32bit). 寻找main函数. int __cdecl main(int argc, const char **argv, const char **envp) {char Buffer[128]; // [esp0h] [ebp-94h] BYREFchar *Str1; // [esp80h] [ebp-14h]char *Str2; // [esp84h] [eb…

ROS理论与实践学习笔记——2 ROS通信机制之常用API

"API" 是 "Application Programming Interface" 的缩写,指的是应用程序编程接口。API是一组定义了不同软件组件如何互相通信的规范。它允许不同的软件系统之间共享功能,提供一种标准的方式来访问某个软件组件的功能或数据。 详细内…

JavaScript模块化-CommonJS规范和ESM规范

1 ES6模块化 1.1 ES6基本介绍 ES6 模块是 ECMAScript 2015(ES6)引入的标准模块系统,广泛应用于浏览器环境下的前端开发。Node.js环境主要使用CommonJS规范。ESM使用import和export来实现模块化开发从而解决了以下问题: 全局作用…

《安富莱嵌入式周报》第343期:雷电USB4开源示波器正式发布,卓越的模拟前端低噪便携示波器,自带100W电源的便携智能烙铁,NASA航空航天锂电池设计

周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程 【授人以渔】CMSIS-RTOS V2封装层专题视频,一期视频将常用配置和用法梳理清楚&#xff0…

Win10系统插入带有麦克风的耳机_麦克风不起作用_解决方法_亲测成功---Windows运维工作笔记054

今天我在使用讯飞输入法的时候,想通过讯飞的语音输入法来提高自己的输入效率。 但是这个时候发现一个问题就是我插入我的台式机的是一个带有麦克风的耳机。 但是发现我这个耳机没有办法被电脑识别出麦克风来,所以说就没办法使用讯飞输入法的语音输入功能来直接输入文字了。…

Qt 窗口中鼠标点击事件的坐标探讨

// 鼠标点击事件 void Widget::mousePressEvent(QMouseEvent *event) {/*event->pos()、event->windowPos()和event->localPos()都表示鼠标点击位置在窗口中的位置,它们的值都是一样的,区别在于event->pos()是QPoint类型,event-&…

操作系统-磁盘管理

存储管理中的磁盘管理涉及到几个核心概念:磁道、扇区、磁头、盘面。 磁道:磁盘表面的同心圆,用于记录数据。每个磁道可以存储相同量的信息。 扇区:磁道被进一步划分的更小单元,通常是磁道的最小存储单位。一个常见的扇…

【新闻转载】Storm-0501:勒索软件攻击扩展到混合云环境

icrosoft发出警告,勒索软件团伙Storm-0501近期调整了攻击策略,目前正将目标瞄准混合云环境,旨在全面破坏受害者的资产。 该威胁行为者自2021年首次露面,起初作为Sabbath勒索软件行动的分支。随后,他们开始分发来自Hive…