程序的机器级表示(一)汇编,汇编格式和数据传输指令

系列文章

: 深入理解计算机系统笔记

文章目录

  • 系列文章
  • 3 程序的机器级表示
    • 3.1 历史观点
    • 3.2 程序编码
      • 3.2.1 机器级代码
      • 3.2.2 代码示例
      • 3.2.3 关于格式的注解
    • 3.3 数据格式
    • 3.4 访问信息
      • 3.4.1 操作数指示符
      • 3.4.2 数据传送指令
      • 3.4.3 数据传送示例
      • 3.4.4 压入和弹出栈数据

3 程序的机器级表示

  • 计算机执行机器代码,编译器基于编程语言的规则、目标机器的指令集,操作系统遵循的惯例生成机器代码。
  • 汇编代码是机器代码的文本表示。高级代码可移植性较好,而汇编代码与特定机器密切相关
  • 现在不要求使用汇编语言编制程序,能够阅读和理解编译器转化的汇编语言的细节和方式,并分析代码中隐含的低效率。
  • 精通细节是理解更深和更基本概念的先决条件

3.1 历史观点

  • Intel处理器系列俗称x86,每个后续处理器都是向下兼容的(所以指令集中会有一些奇怪的东西),x86(64位)
  • 摩尔定律: 晶体管数目18个月翻一番。

3.2 程序编码

  • 使用较高级别优化的代码会严重变形(和源代码的格式),机器代码和初始源代码之间的关系难以理解。实际中,从程序性能考虑,较高级别的优化是较好的选择(O2用的比较多)。
  • 汇编器产生的目标代码是机器代码的一种形式,它包含二进制形式表示的所有指令,但还没有填入全局值的地址。链接之后才形成可执行代码,可执行代码是机器代码的第二种形式

3.2.1 机器级代码

  • 对机器级编程尤为重要的两种抽象
    1.指令集架构:定义了处理器状态、指令的格式、指令对状态的影响。
  1. 虚拟地址:机器级程序使用虚拟地址,即将内存看成一个按字节寻址的数组。
  • 一些通常对语言级隐藏的处理器状态(机器级可见)
  1. 程序计数器(PC):下一条执行指令的地址
  2. 整数寄存器文件:保存临时数据或重要的程序状态
  3. 条件码寄存器:最近执行的算术或逻辑指令的状态信息
  4. 一组向量寄存器:保存一个或多个整数或浮点数值
  • 机器代码和汇编代码中不区分有符号数和无符号数,不区分指针的不同类型,不区分指针和整数。
  • 因为虚拟内存的大小通常比较大,程序实际使用和访问的内存大小通常远小于虚拟内存看起来的大小。所以在任意的时刻,只有有限的虚拟内存是合法的,操作系统负责管理虚拟内存(通过表翻译为实际的物理地址)。
  • 一条机器指令只执行一个非常基本的操作。

3.2.2 代码示例

#include <stdio.h>// 声明 multstore 函数
void multstore(long x, long y, long *dest);// 声明 mult2 函数
long mult2(long a, long b);int main() {long d;multstore(2, 3, &d);printf("2 * 3 --> %ld\n", d);return 0;
}// 定义 multstore 函数
void multstore(long x, long y, long *dest) {*dest = mult2(x, y);
}// 定义 mult2 函数
long mult2(long a, long b) {long s = a * b;return s;
}

gcc -S a.c -o multstore.s

 //部分汇编,不同优化等级和环境产生的不一样//这个和书上差别有亿点大63 mult2:64 .LFB2:65     .cfi_startproc66     pushq   %rbp67     .cfi_def_cfa_offset 1668     .cfi_offset 6, -1669     movq    %rsp, %rbp70     .cfi_def_cfa_register 671     movq    %rdi, -24(%rbp)72     movq    %rsi, -32(%rbp)73     movq    -24(%rbp), %rax74     imulq   -32(%rbp), %rax75     movq    %rax, -8(%rbp)76     movq    -8(%rbp), %rax77     popq    %rbp78     .cfi_def_cfa 7, 879     ret80     .cfi_endproc
  • -S选项产生汇编代码
  • 反汇编是根据机器代码反推出汇编的,逆向和一些安全漏洞分许就会用到这个
  • 机器代码与反汇编表示的特性:
  1. x86-64 的指令长度范围为 1~15 字节常用指令和操作数少的指令所需字节少。
  2. 指令格式设计方式为:可以将字节唯一的解码成机器指令。
  3. 反汇编器基于机器代码文件中的字节序列确定汇编代码,与源代码和编译时的汇编代码无关
  4. 指令结尾的 ‘q’ 是大小指示符,大多数情况下可以省略。
  • 从源程序转换来的可执行目标文件中,除了程序过程的代码,还包含启动和终止程序的代码,与操作系统交互的代码。

3.2.3 关于格式的注解

 81 .LFE2:82     .size   mult2, .-mult283     .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"84     .section    .note.GNU-stack,"",@progbits

像这样的汇编代码,以 ‘.’ (点) 开头的行是指导汇编器和链接器工作的伪指令。我们一般忽略它们。

  • 在汇编语言中,Intel 和 AT&T 是两种主要的语法格式它们在指令格式、操作数顺序、寄存器命名等方面有显著的区别。
  1. Intel 语法: 目的操作数在前,源操作数在后。
    AT&T 语法: 源操作数在前,目的操作数在后。
  2. 操作数大小
    Intel 语法: 操作数大小由操作码决定,不需要额外的后缀。
    AT&T 语法: 使用后缀来指明操作数大小(b 表示字节,w 表示字,l 表示双字,q 表示四字)。
  3. 寄存器命名
    Intel 语法: 寄存器名称直接使用。
    AT&T 语法: 寄存器名称前面加 % 符号。
  4. 立即数
    Intel 语法: 立即数不需要前缀。
    AT&T 语法: 立即数前面加 $ 符号
  • 还有一些符号上的小差距,总的来说两者操作数顺序恰好相反,
  • 我个人觉得Intel语法在许多方面更加简洁
  • 有些C语言访问不到的机器特性,我们可以考虑包含(asm伪指令)或者链接一部分汇编指令来优化程序

3.3 数据格式

在这里插入图片描述
汇编代码指令最后一个字符的后缀:movb, movw, movl, movq。
这里说的都是整数,浮点数使用一组完全不同的指令和寄存器,“l”既可以表示四字节整数,也可以表示8字节的双精度浮点数。

3.4 访问信息

在这里插入图片描述

  • 名称
  1. 起初的8086只有8个16位的寄存器:%ax到%bp (r是特殊的栈指针)
  2. 后面IA32架构扩展至32位,前缀一个e,也就是%eax到%ebx
  3. x86-64架构扩展至16个64位,自带一个r,大小由尾缀决定,编号也挺草率的,几个版本主打一个风格迥异
  • 低位操作的规则
  1. 将寄存器作为目标位置时,生成字节和字的指令会保持剩下的字节不变。(放字节,字(2字节)的时候就不改其他位的值了)
  2. 生成双字的指令会把高位四字节置为 0。(32位扩展的一部分内容
  • 16个寄存器的作用
    a:返回值
    s:栈指针
    d, s, d, c, 8, 9:第 1 到第 6 个参数
    b,bp, 12~15:被调用者保存
    10, 11:调用者保存

3.4.1 操作数指示符

  • 三种主要的操作数类型:
  1. 立即数 (Immediate),表示常数值
    考研好像是Intel格式
//Intel 语法示例
mov eax, 10   ; 将立即数 10 移动到寄存器 eax
add eax, 5    ; 将立即数 5 加到寄存器 eax
//AT&T 语法示例
movl $10, %eax   ; 将立即数 10 移动到寄存器 eax
addl $5, %eax    ; 将立即数 5 加到寄存器 eax
  1. 寄存器 (Register),使用寄存器中的全部位或者低位的内容
//Intel 语法示例
mov eax, ebx   ; 将寄存器 ebx 的值移动到寄存器 eax
add eax, ecx   ; 将寄存器 ecx 的值加到寄存器 eax
//AT&T 语法示例
movl %ebx, %eax   ; 将寄存器 ebx 的值移动到寄存器 eax
addl %ecx, %eax   ; 将寄存器 ecx 的值加到寄存器 eax
  1. 内存引用 (Memory Reference),寻址,可以是直接地址、间接地址或基于寄存器的地址计算。带了()或者[],和解引用指针很像
//Intel 语法示例
mov eax, [ebx]          ; 将内存地址 [ebx] 的值移动到寄存器 eax
mov [ecx + 4], edx      ; 将寄存器 edx 的值移动到内存地址 [ecx + 4]
add eax, [esi + edi*4]  ; 将内存地址 [esi + edi*4] 的值加到寄存器 eax
//AT&T 语法示例
movl (%ebx), %eax            ; 将内存地址 (%ebx) 的值移动到寄存器 eax
movl %edx, 4(%ecx)           ; 将寄存器 edx 的值移动到内存地址 4(%ecx)
addl (%esi, %edi, 4), %eax   ; 将内存地址 (%esi, %edi, 4) 的值加到寄存器 eax

在这里插入图片描述

  • 最后一种最常用也最重要(其他格式是它的一个特例)
  • Imm(rb, ri, s)
  • Imm(立即数偏移) + R[rb] (基址) + R[ri] (变址)s (比例因子)
  • s 只能是 1,2,4,8 中的一个

3.4.2 数据传送指令

  • 简单的四种mov指令
    movb, movw, movl,movq:传送字节、字、双字、四字
  • movabsq(move absolute quadword):传送绝对的四字。用于将一个 64 位的立即数传送到一个 64 位寄存器中。用于初始化寄存器或处理大数机器码九字节(1+8),较大。
  • mov的五种组合:
  1. 立即数到寄存器 (Immediate to Register)
    将一个立即数传送到一个寄存器中。
  2. 立即数到内存 (Immediate to Memory)
    将一个立即数传送到一个内存位置中。
  3. 寄存器到寄存器 (Register to Register)
    将一个寄存器的值传送到另一个寄存器中。
  4. 内存到寄存器 (Memory to Register)
    将一个内存位置的值传送到一个寄存器中。
  5. 寄存器到内存 (Register to Memory)
    将一个寄存器的值传送到一个内存位置中。
  • 示例
	; Intel 语法; 立即数到寄存器mov eax, 10; 立即数到内存mov [var1], 20; 寄存器到寄存器mov ebx, eax; 内存到寄存器mov ecx, [var1]; 寄存器到内存mov [var2], ebx; AT&T 语法; 立即数到寄存器movl $10, %eax; 立即数到内存movl $20, var1; 寄存器到寄存器movl %eax, %ebx; 内存到寄存器movl var1, %ecx; 寄存器到内存movl %ebx, var2
  • 较小的源值复制到较大的目的地使用movz或者movs
    他们的后缀字符第一个指定源的大小,第二个指定目的大小
    movz,将剩余部分填充为0。
    movs,将剩余部分填充为符号位。
    在这里插入图片描述

3.4.3 数据传送示例

  • 3.4.2已经示范差不多了
  • 局部变量通常保存在寄存器中。
  • 函数返回指令 ret 返回的值为寄存器 rax 中的值
  • 强制类型转换可通过 mov 指令实现的。
  • 当指针存在寄存器中时,a = p 的汇编指令为: mov (rdi), rax

3.4.4 压入和弹出栈数据

  • 栈:向下增长(所以压栈时减[%rsp]),后进先出
  • push:压栈
  • pop:出栈
  • %rsp:(64位) 栈指针,栈顶元素的地址
  • 指令尾缀代表操作的大小(bwlq)
  • 其实压栈操作等价于先减栈指针值,再将指定寄存器的值写入栈,反之,出栈先读出栈顶数据到指定寄存器,在加栈指针的值。而push,pop只被编码为一个字节即可完成这两步需要8个字节指令大小的操作。
    在这里插入图片描述
  • 使用 mov 指令和标准的内存寻址方法可以访问栈内的任意位置,而非仅限于栈顶。

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

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

相关文章

达梦数据库系列—30. DTS迁移Mysql到DM

目录 1.MySQL 源端信息 2.DM 目的端信息 3.迁移评估 4.数据库迁移 4.1源端 MySQL 准备 4.2目的端达梦准备 初始化参数设置 兼容性参数设置 创建迁移用户和表空间 4.3迁移步骤 创建迁移 配置迁移对象及策略 开始迁移 对象补迁 5.数据校验 统计 MySQL 端对象及数…

Unity: TextMeshPro生成中文字体(附3.5k,7k,2w常用字集)

免费常用3千5&#xff0c;7千字&#xff0c;2万字中文字体包 1.选择Window/TextMeshPro/Font Asset Creator 注&#xff1a;准备字体&#xff1a;从字体库或其他来源获取中文字体文件&#xff0c;通常为.ttf、.otf或.ttc格式。最简单的方式是从Windows系统文件的Font文件夹里…

应用层自定义协议与序列化

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 协议 简单来说&#xff0c;就是通信双方约定好的结构化的数据。 序列化与反序列化 我们通过一个问题引入这个概念&#xff0c;假如我们要实现一个网络版的计算器&#xff0c;那么现在有两种方案&#xff0c;第一种&#x…

C语言超市管理系统UI界面

以下是部分代码。需要源码的私信 #include<easyx.h> #include<stdio.h> #include<stdlib.h>#define width 1280 #define height 840 #define font_w 35 //字体宽度 #define font_h 90 //字体高度typedef struct node {char name[100];//名字char number[1…

Modbus转Ethernet/IP网关模块与汇川PLC通讯案例

Modbus转Ethernet/IP网关模块&#xff08;XD-MDEP100&#xff09;是一种用于将Modbus协议转换为Ethernet/IP协议的设备。它可以将Modbus RTU和Modbus TCP两种不同格式的Modbus数据包转换为Ethernet/IP协议的数据包&#xff0c;实现不同厂家的设备之间的数据交换和共享。在汇川P…

软件测试----概念篇(笔试相关,一般考察开发模型和测试模型的特点及适用场景)

文章目录 前言一、需求二、开发模型1.什么是“模型”2.软件的生命周期3.常见开发模型瀑布模型螺旋模型增量模型、迭代模型敏捷模型 三、测试模型V模型W模型(双V模型&#xff09; 前言 在当今软件行业飞速发展的时代&#xff0c;软件测试已成为软件质量保障的重要环节。它贯穿于…

WhisperX

文章目录 一、关于 WhisperX新闻 &#x1f6a8; 二、设置⚙️1、创建Python3.10环境2、安装PyTorch&#xff0c;例如Linux和Windows CUDA11.8&#xff1a;3、安装此repo4、Speaker Diarization 三、使用&#x1f4ac;&#xff08;命令行&#xff09;1、English2、他语言例如德语…

Cyber Weekly #16

赛博新闻 1、OpenAI 发布 GPT-4o mini OpenAI 本周官宣推出 GPT-4o mini&#xff0c;这是 GPT-4o 更小参数量的简化版本。ChatGPT 的免费用户、Plus 用户和 Team 用户能使用 GPT-4o mini 而并非 GPT-3.5 Turbo&#xff0c;企业用户在下周也将获得 GPT-4o mini 的权限。GPT-4o…

少儿编程启蒙宝典:Scratch动画游戏108变

一、编程教育的时代价值与意义 随着数字时代的深入发展&#xff0c;社会对人才的需求正发生深刻变革&#xff0c;计算思维与编程能力已成为衡量个人竞争力的重要指标。在此背景下&#xff0c;培养孩子们运用计算思维解决实际问题的能力&#xff0c;成为教育领域的重要任务。编…

UE4-获得角色控制权的两种方法

方法一&#xff1a; 方法二&#xff1a; 注意此方法不能有多个玩家出生点&#xff0c;如果有多个玩家出生点&#xff0c;会随机的选择一个玩家出生点进行生成。

IP5306移动电源DIY

最近制作一款移动电源&#xff0c;芯片采用的是IP5306

UDP详细总结

UDP协议特点 UDP是无连接的传输层协议&#xff1b; UDP使用尽最大努力交付&#xff0c;不保证可靠交付&#xff1b; UDP是面向报文的&#xff0c;对应用层交下来的报文&#xff0c;不合并&#xff0c;不拆分&#xff0c;保留原报文的边界&#xff1b; UDP没有拥塞控制&#…

python实现图像对比度增强算法

python实现直方图均衡化、自适应直方图均衡化、连接组件标记算法 1.直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 2.自适应直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 3.连接组件标记算法详解算法步骤8连通与4连通公式Python 实现详细解释优缺…

微服务实现全链路灰度发布

一、实现步骤 再请求 Header 中打上标签&#xff0c;例如再 Header 中添加 "gray-tag: true" &#xff0c;其表示要进行灰度测试&#xff08;访问灰度服务&#xff09;&#xff0c;而其他则访问正式服务。在负载均衡器 Spring Cloud LoadBalancer 中&#xff0c;拿到…

Deepin系统,中盛科技温湿度模块读温度纯c程序(备份)

#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <termios.h>int main() {int fd;struct termios options;// 打开串口设备fd open("/dev/ttyMP0", O_RDWR | O_NOCTTY|O_NDELAY); //O_NDELAY:打开设备不阻塞//O_NOCTT…

Qt Creator配置以及使用Valgrind - 检测内存泄露

Qt Creator配置以及使用Valgrind - 检测内存泄露 引言一、下载安装1.1 下载源码1.2 安装 二、配置使用2.1 Qt Creator配置2.2 使用2.3 更多详细信息可参考官方文档&#xff1a; 三、参考链接 引言 Valgrind是一个在Linux平台下广泛使用的开源动态分析工具&#xff0c;它提供了一…

任务2:python+InternStudio 关卡

任务地址 https://github.com/InternLM/Tutorial/blob/camp3/docs/L0/Python/task.md 文档 https://github.com/InternLM/Tutorial/tree/camp3/docs/L0/Python 任务 Python实现wordcount import re import collectionstext """ Got this panda plush to…

【机器学习】智能驱动未来:机器学习在能源效率提升与环境管理中的创新应用

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习能源环境领域的应用潜力&#x1f304;能源效率提升&#x1f3de;️环境管理⛰️具体案例…

Linux之旅:常用的指令,热键和权限管理

目录 前言 1. Linux指令 &#xff08;1&#xff09; ls &#xff08;2&#xff09; pwd 和 cd &#xff08;3&#xff09;touch 和 mkdir &#xff08;4&#xff09; rmdir 和 rm &#xff08;5&#xff09;cp &#xff08;6&#xff09;mv &#xff08;7&#xff09;…

开发工具推荐:await-to-js

目录 前言&#xff1a; 1. .then().catch() 2. async await 3. await-to-js 前言&#xff1a; 今天给大家推荐一块我觉得用着还不错的工具&#xff0c;await-to-js&#xff1b; await-to-js - npm GitHub - scopsy/await-to-js: Async await wrapper for easy error ha…