首页 > 其他分享 >101 - Lecture 9

101 - Lecture 9

时间:2024-10-20 21:21:43浏览次数:6  
标签:汇编 ESP 寄存器 指令 printf 堆栈 Lecture 101

CPU的内部操作,包括寄存器、堆栈和指令执行过程

CPU Registers

CPU寄存器
• CPU寄存器是CPU内用于临时存储数据的特殊存储器。寄存器的操作速度比主存储器(内存)更快。Pentium处理器中各种寄存器,包括通用寄存器、基地址寄存器、指令指针(EIP)等。

CPU status flags

CPU状态标志(Flags)
• EFLAG寄存器保存了CPU的状态标志(status flags),状态标志是用于存储在算术运算等过程中产生的结果

•如:符号标志(Sign)、零标志(Zero)以及进位标志(Carry)等。

每个标志代表不同的运算状态,如溢出(overflow)、进位(carry bits)等,帮助CPU在不同指令之间传递信息。使得后续指令能够根据前一条指令的结果做出相应的处理。

请添加图片描述

– S: sign.符号位,表示运算结果的正负
– Z: zero, result being zero.
– C: carry, indicates an arithmetic carry.
– O: arithmetic overflow error

在二进制的补码系统(Two’s complement system)中,将两个大的正数相加可能会得到一个负数的结果。这听起来违反直觉,因为在常规的算术中,正数加正数总是得到正数。但在计算机的补码系统中,由于位数的限制和特殊的编码方式,当两个正数相加超过该系统能表示的最大正数时,会发生溢出,从而导致结果变成负数。

关联关键词解析:

  1. 补码系统:补码(Two’s complement)是一种用于表示有符号整数的方法

算术溢出错误(Arithmetic Overflow Error)

二进制数相加时发生溢出的情况。当两个数相加的结果超出了能够表示的位数范围时,产生溢出。触发了溢出标志(OF will be set)。

请添加图片描述

请添加图片描述

CPU标志位(CPU Flags)的操作。具体来说,它展示了CMP指令和JZ指令的操作:

•	CMP(比较):比较两个值,将结果通过减法(subtract)得出,但不会保存结果,只会设置标志位,比如零标志(Z flag)。
•	JZ(条件conditional跳转jump):根据Z标志位的状态进行条件跳转。如果Z标志被设置,说明两个数相等,JZ会执行跳转。

Inline Assembler(内联汇编):

• 内联汇编器:
我们会在Microsoft Visual C++环境下使用内联汇编器。所谓内联汇编就是在C/C++代码中直接插入汇编语言代码,使其能够在编译时与C/C++代码一起编译和执行。相比独立的汇编程序,内联汇编具有与C/C++语言无缝结合的优点

• 汇编代码(assembly code)引用(refer to)C/C++变量:
在内联汇编中,可以直接引用C/C++的变量。

例如: _asm mov eax,var

var是C/C++中的变量名,而汇编指令mov eax,var将该变量的值存入EAX寄存器中。

语法规则:内联汇编

1.可以使用_asm关键字来嵌入单行汇编代码。如果是多行汇编代码,可以使用带花括号的_asm{…}。
2. 汇编代码中的注释可以使用分号;,类似C/C++中的//注释。也可以在汇编代码中使用//来注释。

• 调用C函数:通过使用_asm{…}的语法,可以在汇编代码中调用C语言函数,包括标准的C库函数。这意味着我们可以在汇编代码中使用类似printf和scanf这样的C函数。C library routines

• 使用堆栈(stack)传递参数:当我们调用printf或其他类似函数时,参数是通过堆栈传递的。

堆栈是函数调用时保存局部变量和函数参数的重要数据结构。

printf 和 scanf

printf("%d\n", x);用于输出整数x,其中%d是格式说明符,表示输出整数值。

scanf("%d %s %d", &day, monthname, &year);
%d用于整数,%s用于字符串。读取的数据分别存储在day、monthname和year变量中。

• printf 和 scanf 通常结合使用,先用 printf 提示用户输入信息,然后使用 scanf 接受用户输入。

int x;
printf("Enter a value for x: ");
scanf("%d", &x);
printf("You entered: %d\n", x);

& 是 取地址符(address-of operator)。它的作用是返回变量在内存中的地址,而不是变量本身的值。我们可以通过这个符号获取一个变量的地址,并将这个地址传递给像 scanf 这样的函数,这样函数就可以直接操作存储在该地址上的数据

printf 用于输出数据,scanf 用于从用户输入中读取数据。

堆栈(Stack)

1. Stack的定义和特性:

Stack is a memory arrangement(data structure)
• 堆栈是一种内存排列方式(数据结构),用于存储和检索(retrieval)信息(通常是值或变量)。它的存储和检索顺序可以描述为LIFO(Last In, First Out),即后进先出(后进去的数据最先被取出来)。栈常用于函数调用、撤销操作等场景。

• ESP(栈指针寄存器)(stack pointer register)用于存储堆栈顶端项的地址。

• 队列(Queue)是与堆栈不同的另一种数据结构(memory arrangement),遵循FIFO(First In, First Out),即先进先出。

堆栈的基本操作:PUSH 和 POP:

• 每个堆栈都有两个基本操作:PUSH(压入)和POP(弹出)

• PUSH操作将一个值压入堆栈,POP操作从堆栈弹出一个值。

请添加图片描述

当数据被推入(push)堆栈时,ESP寄存器的值会减小,当数据从堆栈中弹出(pop)时,ESP寄存器的值会增加。ESP寄存器对于管理函数调用、变量存储和程序执行中的各种临时数据非常重要。

1. 堆栈在汇编语言中的实现:

• 堆栈是一个简单但非常有用的数据结构。几乎所有汇编语言都有专门的指令来实现堆栈操作。

• 在内联汇编(Inline Assembly)中,PUSH和POP操作使用栈指针寄存器ESP来存储栈顶元素的地址。
• 通过PUSH和POP指令,可以分别压入和弹出数据,并通过ESP寄存器管理堆栈。

2. 倒置堆栈的假设与PUSH和POP的具体工作原理:

•	这里假设堆栈在内存中是“倒置”(upside-down stack)的,意思是地址从高到低排列。

•	PUSH操作的具体步骤是:
1.	通过减少ESP中的地址,腾出堆栈空间。
2.	然后使用ESP中的地址将值写入堆栈。

•	POP操作的具体步骤是:
4.	使用ESP中的地址读取堆栈中的值。
5.	然后通过增加ESP中的地址来移除堆栈中的项。

请添加图片描述

• PUSH EAX:将EAX寄存器中的32位值压入堆栈。
• CALL print:执行一个子程序,该子程序与堆栈无关,但展示了堆栈在函数调用中的常见使用。
• POP EBX:从堆栈中弹出32位数据,并将其存储到EBX寄存器中。

Adjusting stack pointer

在编写程序时,程序员有时需要手动调整堆栈指针(stack pointer)。
堆栈指针指向堆栈顶部的数据项。在某些情况下,程序员可能需要从堆栈中移除数据项,或者为即将存入堆栈的数据预留空间。
例如,在汇编语言中,可以使用 “ADD ESP,4” 指令来从堆栈中移除(或者说“弹出”)4个字节的数据。这样做通常是为了清理堆栈上之前操作留下的数据。
“SUB ESP,256” 指令则是用来在堆栈上创建256字节的空间,这在需要存储大量临时数据时非常有用。

Stack as the temporary store

栈作为临时存储的功能,特别是如何在C语言中结合汇编语言来使用栈保存循环计数器和参数。

•	mov ecx, 10:将循环计数器ecx初始化为10。
•	push ecx:将当前循环计数器的值(10)压入栈中,保存起来。
•	lea eax, format:加载字符串地址到寄存器eax。
•	push eax:将字符串的地址压入栈中,作为printf函数的参数。
•	call printf:调用printf函数打印“Hello World”。
•	add esp, 4:清理栈,释放printf的参数所占用的空间。
•	pop ecx:从栈中恢复保存的循环计数器值到寄存器ecx。
•	loop Lj:减少ecx的值,如果ecx不为0,则跳转回标记Lj,重复上述操作。

这个程序展示了如何使用栈来暂时保存循环计数器ecx的值,以便ecx寄存器可以用于其他目的,同时在循环结束后恢复其值。

• 栈被用作“scratch-pad”(临时记事本)来存储循环计数器的值,以便释放寄存器(free ECX register)用于其他用途。
• 这是栈的常见使用场景,特别是在需要临时保存变量的场合,栈可以用于存储和恢复这些值。

Passing parameters

• 堆栈除了用于存储数据外,还可以用于传递函数参数。printf函数的参数通过堆栈传递,而使用ESP指令调整堆栈以清除参数。

printf是一个常见的用于格式化输出的函数,在C语言中广泛使用。在使用printf进行打印时,需要提供两个方面的信息:
一是要打印的内容
二是打印的格式
这些信息通常通过参数(parameters)的形式传递给printf函数。

It misdone via stack

push eax将要打印的字符串地址放到栈上
call printf读取栈顶(the top of the stack)的地址并打印出字符串
printf执行完后不会自动移除栈顶的地址
因此需要使用add esp, 4来清理(clean)栈,移除这4个字节的参数。
否则,栈中的数据会保持不变,影响后续操作

Q&A

  1. 列出Pentium处理器中Flag寄存器的3个使用场景:
    • Flag寄存器可以在以下场景中使用:
    1. 条件跳转操作(例如,使用CMP指令后,通过零标志判断两个值是否相等)。
    2. 算术操作中检测溢出(通过溢出标志位检测溢出)。
    3. 中断处理(设置或清除中断标志来控制中断)。
  2. Flag寄存器可以用于在一条指令和后续指令之间传递信息(对或错?):
    • 答案:对。
  3. 哪一个寄存器用于存储此指令的减法结果?CMP AL, BL:
    • 答案:AL寄存器(AL为目标寄存器,存储比较结果的标志位会反映在Flag寄存器中)。
  4. 在内联汇编中,如何传递参数给printf:
    • 这里的问题是关于在内联汇编中,如何将参数传递给printf函数,正确的方式是通过堆栈(stack)来传递参数,利用push eax等操作将值压入堆栈。printf读取栈上的参数地址进行输出。
    5. 内联汇编可以调用C库函数(True or False):
    • True。
  5. 状态标志在指令执行之前是否被设置:
    • 实际上,状态标志是在指令执行之后根据结果进行更新的,False。
  6. D标志用于设置循环方向:
    • D标志通常用于控制字符串操作指令(如MOVSB、STOSB)中的递增或递减方向。

标签:汇编,ESP,寄存器,指令,printf,堆栈,Lecture,101
From: https://blog.csdn.net/gyh101010/article/details/143092127

相关文章

  • 101 - Lecture 8
    汇编语言、指令执行、CPU寄存器和内存Executionofinstructions指令执行取指-执行循环(fetch-executioncycle):•CPU遵循“取指-执行”循环。取指阶段对于所有指令都是一致的,而执行阶段则取决于指令的类型。指令类型:•CPU使用不同类型的指令,这些指令可以组合起来完......
  • 111 - Lecture 5
    Decomposition,AbstractionandFunctions1.编程中的基础语言机制(basiclanguagemechanisms):回顾我们已经学习的Java基本语法,包括:•Primitives原始数据类型(byte,short,int,long,float,double,boolean,char)•complexexpressions复杂表达式•branching......
  • 二维数组1019
    publicclassPlaceDemo{publicstaticvoidmain(String[]args){//班级学生座位(二维数组)place();pace();}publicstaticvoidplace(){//静态初始化数组-----数据类型[][]数组名=new数据类型[]{元素1,元素2,元素3,··......
  • 数组练习1018
    假设班级有8名学生,录入8名学生的java成绩,成绩类型是小数,并输出平均分,最高分,最低分publicclassClassDemo2{publicstaticvoidmain(String[]args){//假设班级有8名学生,录入8名学生的java成绩,成绩类型是小数,并输出平均分,最高分,最低分studentSc......
  • [20241018]21c x$mutex_sleep_history记录的变化.txt
    [20241018]21cx$mutex_sleep_history记录的变化.txt--//mutex很少会成为主要等待事件,如果遇到多数情况非常特别,比如bug。mutex本身和保护对象是一体的,不像latch一样有单独的--//latch,而且mutex本身占内存也更小,mutex没有等待和持有队列,所以没有排队机制,mutex具有共享和排它......
  • 20241019
    这两天的题和今天的考试题。都是城外的今天考试爆蛋了。【探险队】题意:思路:发现这是个基环树森林,考虑怎么做。发现如果是一条链的话很好做,直接一选一不选就行了,那就可以先这样把基环树都搞成一个个环。然后想到对于一个环可能它之前连着个链,然后最后一个被选了,这就导致环上这......
  • Leecode热题100-101.对称二叉树
    给你一个二叉树的根节点 root ,检查它是否轴对称。示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:false提示:树中节点数目在范围 [1,1000] 内-100<=Node.val<=100进阶:你可以运用递归和迭代两种方法解决这个问......
  • SS241019B. 染色(color)
    SS241019B.染色(color)思路首先观察结果序列长什么样子,且思考如何去重。结果序列是若干段长度若干的颜色拼成的,满足颜色序列是原序列的一个子序列,如111555334可以是123453345的一个合法结果,对应的颜色序列是1534。为了去重,要求颜色序列不存在两个相邻的颜色。发现可以转换......
  • 20241019CSAD架构
    两种不同模态的MR图像(即T2和ADC)被发送到双流编码器子网络中。在训练期间,注意力图生成块(AMGB)生成的注意力图用于实现CSAD,而输入图像和相应的掩码用于优化编码器-解码器网络以完成分割任务。在编码器子网络的每个中间层,添加一组注意力图生成块(AMGB)来实现跨模态自注意......
  • Java面向对象学习1019-1
    Java面向对象基础1:  面向对象编程是什么,和面向过程有什么区别?  面向对象编程OOP(ObjectOrientedPrograming)是一种程序设计方法,其本质是模仿人的思维来解决问题,把客观世界的实体抽象为对象。不同于面向过程编程POP(ProcedureOrientedPrograming)以过程为中心,关注......