结构体,联合体,指针和浮点代码笔记

news2024/9/17 3:50:42

系列文章

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

文章目录

  • 系列文章
    • 3.9 异质的数据结构
      • 3.9.1 结构
      • 3.9.2 联合
      • 3.9.3 数据对齐
    • 3.10 在机器级程序中将控制和数据结合起来
      • 3.10.1 理解指针
      • 3.10.2 应用:使用GDB调试器
      • 3.10.3 内存越界引用和缓冲区溢出
      • 3.10.4 对抗缓冲区溢出攻击
      • 3.10.5 支持变长栈帧
    • 3.11 浮点代码
      • 3.11.1 浮点传送和转换操作
      • 3.11.2 过程中的浮点代码
      • 3.11.3 浮点运算操作
      • 3.11.4 定义和使用浮点常数
      • 3.11.5 在浮点代码中使用位级操作
      • 3.11.6 浮点比较操作
      • 3.11.7 对浮点代码的观察结论
    • 3.12 小结

3.9 异质的数据结构

  • struct和union

3.9.1 结构

  • 结构的所有组成部分存放在连续的空间中,编译器维护每个结构的信息,指示每个字段的字节偏移,将偏移作为内存引用指令中的位移,从而引用结构元素
struct rec {
    int i;
    int j;
    int a[2];
    int *p;
};
//
r->p = &r->a[r->i + r->j];
//汇编实现
1. movl 4(%rdi), %eax      # Get r->j
2. addl (%rdi), %eax       # Add r->i
3. cltq                    # Extend to 8 bytes
4. leaq 8(%rdi, %rax, 4), %rax  # Compute &r->a[r->i + r->j]
5. movq %rax, 16(%rdi)     # Store in r->p

3.9.2 联合

  • 不同的字段引用相同的内存块,字段是互斥的,将各种不同大小的数据类型结合到一起时字节序很重要

3.9.3 数据对齐

  • 基本思想:将数据成员放置在符合特定对齐边界的地址上,这些对齐边界通常是数据类型的大小的倍数。
  • 对齐规则
  1. 基本对齐:每个数据成员的地址必须是其大小的倍数。例如,一个int类型通常需要在4字节边界上对齐。
  2. 结构体对齐:整个结构体的起始地址也要遵循一定的对齐规则,这个规则通常是结构体中最大成员的对齐要求
  • 结构体对齐的原因
  1. 提高访问速度:现代处理器通常在读取内存时会加载整块数据(例如一个64位系统一次可能加载64位的数据)。如果数据未对齐,处理器可能需要进行额外的读取和拼接操作,导致性能下降。
  2. 硬件要求:某些硬件架构要求数据必须按照特定的对齐方式存储,否则会导致硬件错误或性能大幅下降。
//修改结构体对齐为1字节
#pragma pack(push, 1)
  • x86-64的16字节对齐:内存分配,栈帧边界,特殊的指令

3.10 在机器级程序中将控制和数据结合起来

3.10.1 理解指针

  • 指针:对不同数据结构中的元素产生引用,指针映射到机器代码的关键原则
  1. 每个指针都对应一个类型,这是C语言提供的一种抽象
  2. 每个指针都有一个值,这个值是指定对象的地址
  3. &取地址运算符创建指针
  4. *间接引用
  5. 数组和指针关系精密,数组名即首元素地址
  6. 指针强转改变类型(运算和解释方式),不改变值
  7. 指针可以指向函数并调用函数

3.10.2 应用:使用GDB调试器

在这里插入图片描述

3.10.3 内存越界引用和缓冲区溢出

  • C对数组引用不进行任何边界检查,且局部变量和状态信息都存放在栈中,对越界数组元素的写操作会破坏存储在栈中的状态信息

3.10.4 对抗缓冲区溢出攻击

  1. 栈随机化(Stack Randomization),通常指的是地址空间布局随机化(Address Space Layout Randomization,ASLR)中的一种技术。防止安全单一化(被一种方式攻击多个系统)。栈随机化在Linux系统中,可以通过/proc/sys/kernel/randomize_va_space文件来控制ASLR的启用与否。也需要编译器的支持。使栈的位置每次运行都在变化,但是需要提前分配多余的空间,所以空间不会太大,容易被“空操作雪橇(nop sled)”暴力破解
  2. **栈破坏检测(Stack Smashing Protection)**检测何时栈被破坏。
    栈保护者(stack protector),在局部缓冲区和栈状态之间存储随机生成的栈金丝雀(Stack Canary)函数返回时,程序会检查这个金丝雀值是否被修改(是不是和内存段中的一样)。如果检测到金丝雀值被更改,程序会终止并返回错误信息。在有保护的程序中,局部变量比buf更接近栈顶,buf溢出就不会破坏值,在溢出方向和状态信息间插入金丝雀值检测溢出。
  3. 限制可执行代码区域(Executable Space Protection通过将内存区域标记为不可执行,从而防止攻击者利用漏洞向这些区域注入并执行恶意代码,NX位(No-eXecute bit)不执行位,DEP(Data Execution Prevention)操作系统级,W^X(Write XOR Execute)读或者写

3.10.5 支持变长栈帧

  • ebp基址和esp
push ebp                 ; 保存基址指针
mov ebp, esp             ; 设置新的基址指针
sub esp, n               ; 分配n字节的栈空间
; 函数体
mov esp, ebp             ; 恢复栈指针
pop ebp                  ; 恢复基址指针
ret                      ; 返回

3.11 浮点代码

  • 处理器的浮点体系结构包括:
    • 如何存储和访问浮点数值
    • 对浮点数操作的指令
    • 向函数传递浮点数参数和从函数返回浮点数结果的规则
    • 函数调用过程中保存寄存器的规则
  • AVX浮点体系
    在这里插入图片描述

3.11.1 浮点传送和转换操作

  • 内存和XMM寄存器之间及寄存器之间传送浮点数的指令,内存引用的指定方式与整数MOV指令相同
  • s(单精度)d(双精度)a(对齐的,不满足16字节对齐会导致异常)
    在这里插入图片描述
  • 浮点数与整数类型和不同浮点格式的转换指令,浮点转整数时,会截断并向0舍入
    在这里插入图片描述

3.11.2 过程中的浮点代码

  • XMM寄存器向函数传递浮点数参数的规则
    • 寄存器%xmm0-7最多可以传递8个浮点数参数
    • 使用寄存器%xmm0返回浮点值
    • 所有的XMM寄存器都是调用者保存,被调用者不用保存就可以覆盖

3.11.3 浮点运算操作

在这里插入图片描述

double funct(double a, float x, double b, int i) {
    return a * x - b / i;
}
// x86-64 代码如下:
funct:
    vunpcklps %xmm1, %xmm1, %xmm1       // 将x从单精度浮点转换为双精度浮点的第一步
    vcvtps2pd %xmm1, %xmm1              // 将x从单精度浮点转换为双精度浮点的第二步
    vmulsd %xmm0, %xmm1, %xmm0          // 计算 a * x
    vcvtsi2sd %edi, %xmm1, %xmm1        // 将i转换为双精度浮点
    vdivsd %xmm1, %xmm2, %xmm2          // 计算 b / i
    vsubsd %xmm2, %xmm0, %xmm0          // 计算 a * x - b / i
    ret

3.11.4 定义和使用浮点常数

  • 和整数运算不同,AVX浮点操作不能以立即数作为操作数,也就是说编译器要为所有的常量值分配和初始化存储空间,并使用加载指令将这些常量值载入寄存器

3.11.5 在浮点代码中使用位级操作

  • 位级异或vxorps,vorpd D<—S2^S1
  • 位级于vandps,andpd D<—S2&S1

3.11.6 浮点比较操作

  • ucomiss(ucomisd) S1,S2 效果S2 - S1
    类似于CMP指令,S2必须在XMM寄存器,S1可以在内存
  • 三个条件码:ZF,CF,PE,当两个操作数的任意一个为NaN时是无序的。
    设置条件如下:
    在这里插入图片描述
typedef enum {NEG, ZERO, POS, OTHER} range_t;

range_t find_range(float x) {
    int result;
    if (x < 0)
        result = NEG;
    else if (x == 0)
        result = ZERO;
    else if (x > 0)
        result = POS;
    else
        result = OTHER;
    return result;
}
// x86-64 代码如下:
find_range:
    vxorps %xmm1, %xmm1, %xmm1         // Set %xmm1 = 0
    vucomiss %xmm0, %xmm1              // Compare 0:x
    ja .L5                             // If >, goto neg
    vucomiss %xmm0, %xmm0              // Compare x:0
    jp .L8                             // If NaN, goto posornan
    movl $1, %eax                      // result = ZERO
    je .L3                             // If =, goto done
.L8:
    vucomiss .LC0(%rip), %xmm0         // Compare x:0
    setbe %al                          // Set result = NaN ? 1 : 0
    movzbl %al, %eax                   // Zero-extend
    addl $2, %eax                      // result += 2 (POS for > 0, OTHER for NaN)
    ret
.L5:
    movl $0, %eax                      // result = NEG
.L3:
    rep; ret                           // Return

3.11.7 对浮点代码的观察结论

  • AVX2的机器代码风格类似于整数的风格,使用寄存器保存操作以及传递数值,还有能力在封装好的数据上执行并行计算

3.12 小结

  • 本章代码只能在x86-64机器上运行
  • 机器级程序和它们的汇编代码表示,与C程序的差别很大。各种数据类型之间的差别很小。程序是以指令序列来表示的。每条指令都完成一个单独的操作。部分程序状态,如寄存器和运行时栈,对程序员来说是直接可见的。编译器必须使用多条指令来产生和操作各种数据结构,以及实现条件、循环和过程这样的结构。
  • 编译C++与编译C就非常相似。实际上,C++的早期实现就是简单地进行了从C++到C的源到源的转换,并对结果运行C编译器,产生目标代码。尽管C++的对象用结构表示,类似于C的struct。C++的方法是用指向实现方法的代码的指针数组的形式。Java也是相同的。Java的目标代码是一种特殊的二进制编码表示,称为Java字节码,而Java的实现方式完全不同。Java的目标代码可以看成是虚拟机的机器级程序,这种编码并不是直接在硬件处理平台上运行,而是用解释器来处理字节码,模拟机器行为。另外,有一种称为及时编译的方法动态的将字节码翻译成实际机器指令进行执行。当你要执行多次(循环)时,这种方法更快。字节码的优点是相同的代码可以在不同的机器上执行。

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

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

相关文章

(最新)华为 2024 届校招-硬件通⽤/单板开发——第十一套和十二套

&#xff08;最新&#xff09;华为 2024 届校招-硬件通⽤/单板开发——第十一套和十二套 部分题目分享&#xff0c;完整版带答案(有答案和解析&#xff0c;答案非官方&#xff0c;仅供参考&#xff09;&#xff08;共十二套&#xff09;&#xff08;谢绝白嫖哈&#xff09; …

leetcode日记(56)文本左右对齐

不难想但是很难写&#xff0c;需要考虑情况。 我是先写出代码框架&#xff08;先看一行可以加入接下来几个字母和对应空格&#xff0c;然后用空格数和字母数相除取模计算出字母间可以塞多少个空格&#xff0c;循环塞入这些空格和字母&#xff0c;添加进结果中&#xff09;&…

MongoDB教程(二十三):关于MongoDB自增机制

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MongoD…

青少年绘画大赛兰州站:童梦起航 致敬科学 续写降压0号之父强国梦

2024年7月21日&#xff0c;“鹤舞童梦致敬科学精神”青少年绘画大赛在兰州隆重启幕。 活动邀请了多位重量级嘉宾担任评委&#xff0c;包括中国美术家协会会员、甘肃省油画协会常务理事马爱兵&#xff0c;兰州交通大学天佑美术馆馆长王欣&#xff0c;以及国家一级美术师蔡晓斌。…

【Java基础系列】RBAC:介绍与原理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【C++】模板详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

Activiti 本地画流程 http://localhost:8080/activiti-app/#/

http://localhost:8080/activiti-app/#/ 1、本地安装了Tomcat 2、本地安装了Activiti 3、拷贝Activiti中这两个文件到Tomcat中的webapps目录下 4、启动startu.bat 5、http://localhost:8080/activiti-app/#/ 账号&#xff1a;admin 密码&#xff1a;test

Redis-jenkins

1. 什么是jenkins Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。 2. 为什么使用jenkins 使用 Jenkins之前使用 Jenkins之…

【图形图像-1】SDF

在图形图像处理中&#xff0c;SDF&#xff08;Signed Distance Field&#xff0c;带符号的距离场&#xff09;是一种表示图形轮廓和空间距离的数学结构。它通常用于计算机图形学、文本渲染、碰撞检测和物理模拟等领域。 SDF&#xff08;Signed Distance Field&#xff0c;带符号…

白鲸开源CEO郭炜荣获「2024中国数智化转型升级先锋人物」称号

2024年7月24日&#xff0c;由数据猿主办&#xff0c;IDC协办&#xff0c;新华社中国经济信息社、上海大数据联盟、上海市数商协会、上海超级计算中心作为支持单位&#xff0c;举办“数智新质力拓未来 2024企业数智化转型升级发展论坛——暨AI大模型趋势论坛”数据猿“年中特别策…

.h264 .h265 压缩率的直观感受

1.资源文件 https://download.csdn.net/download/twicave/89579327 上面是.264 .265和原始的YUV420文件&#xff0c;各自的大小。 2.转换工具&#xff1a; 2.1 .h264 .h265互转 可以使用ffmpeg工具&#xff1a;Builds - CODEX FFMPEG gyan.dev 命令行参数&#xff1a; …

二叉树详解-第四篇 二叉树链式结构的实现

目录 1.二叉树的遍历 1.1前序遍历&#xff1a; 1.2 中序遍历&#xff1a; 1.3 后序遍历&#xff1a; 2.二叉树链式结构的实现 2.1 Tree.h 2.2 Tree.cpp 2.2.1 前序遍历 void PreOrder(TNode* Root) 2.2.2 中序遍历 void InOrder(TNode* Root) 2.2.3 后序遍历 void Bac…

Linux中断框架

不管是裸机实验还是 Linux 下的驱动实验&#xff0c;中断都是频繁使用的功能&#xff0c;在裸机中使用中断我们需要做一大堆的工作&#xff0c;比如配置寄存器&#xff0c;使能 IRQ 等等。Linux 内核提供了完善的中断框架&#xff0c;我们只需要申请中断&#xff0c;然后注册中…

【rockyLinux】rockyLinux 9.4 安装 java jdk

一、安装 java 1.选择版本 yum list | grep jdk各个版本之间的区别&#xff1a; 2.选择了&#xff1a;java-17-openjdk-devel.x86_64&#xff08;开发者版本&#xff09;&#xff0c;开始安装 建议安装在 /usr/local 这个目录下&#xff0c;可以创建一个 app 目录来收录它…

重生奇迹MU 三个阶段三种体验

重生奇迹MU的玩家们通常按等级分为三个阶段。在这三个不同的阶段里&#xff0c;游戏中的玩家好像深入了三个不同的世界&#xff0c;经历了三种不同的游戏体验&#xff0c;收获了三种不同的精彩&#xff01; 从刚开始游戏一直到达到400级&#xff0c;是游戏中的第一个阶段&…

0719_驱动3 printk使用方法

一、printk使用方法 1.应用层打印使用printf&#xff0c;内核层使用printk 2.如何查看内核层中printk如何使用 3.在内核空间执行grep "printk" * -nR 4.在内核空间执行vi -t KERN_INFO 5.printk有8中打印级别&#xff08;0-7&#xff09;&#xff0c;打印级别用来过滤…

暴雨宅家?AI拯救你的无聊暑假!高中生必藏神器大公开

嘿&#xff0c;各位高中生朋友们&#xff0c;最近是不是被这没完没了的暴雨困在家里&#xff0c;感觉暑假生活都快发霉了&#xff1f;别急&#xff0c;今天我要揭秘一个宝藏网站—— ai123.cn&#xff0c;它简直就是咱们暑期宅家必备的救星&#xff01;接下来&#xff0c;我就来…

Selenium相对定位

测试网站&#xff1a;Web form 相对定位的方法&#xff1a; above()&#xff1a;定位基准元素上方的元素below()&#xff1a;定位基准元素下方的元素to_left_of()&#xff1a;定位基准元素左侧的元素to_right_of()&#xff1a;定位基准元素右侧的元素near() &#xff1a;定位基…

Windows横向渗透

准备靶机windows&#xff1a;192.168.10.131 准备攻击机&#xff1a;192.168.10.130 1.用cs连接到了windows靶机 2.使用cs探测内网信息&#xff1a; 查看当前目标系统网络情况&#xff0c;确认目标系统所在内网网段为10段 3.使用cs的portscan功能对内网进行扫描 portscan 1…

aarch64环境安装minio

1.去官网查看最新版本 MinIO | 用于AI的S3 & Kubernetes原生对象存储 2.使用命令安装,采取wget和dnf安装 wget https://dl.min.io/server/minio/release/linux-arm64/archive/minio-20240113075303.0.0-1.aarch64.rpm -O minio.rpm sudo dnf install minio.rpm 注意点…