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

系列文章

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

文章目录

  • 系列文章
    • 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 * xvcvtsi2sd %edi, %xmm1, %xmm1        // 将i转换为双精度浮点vdivsd %xmm1, %xmm2, %xmm2          // 计算 b / ivsubsd %xmm2, %xmm0, %xmm0          // 计算 a * x - b / iret

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;elseresult = OTHER;return result;
}
// x86-64 代码如下:
find_range:vxorps %xmm1, %xmm1, %xmm1         // Set %xmm1 = 0vucomiss %xmm0, %xmm1              // Compare 0:xja .L5                             // If >, goto negvucomiss %xmm0, %xmm0              // Compare x:0jp .L8                             // If NaN, goto posornanmovl $1, %eax                      // result = ZEROje .L3                             // If =, goto done
.L8:vucomiss .LC0(%rip), %xmm0         // Compare x:0setbe %al                          // Set result = NaN ? 1 : 0movzbl %al, %eax                   // Zero-extendaddl $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://xiahunao.cn/news/3268756.html

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

相关文章

2.1、matlab绘图汇总(图例、标题、坐标轴、线条格式、颜色和散点格式设置)

1、前言 在 MATLAB 中进行绘图是一种非常常见且实用的操作&#xff0c;可以用来可视化数据、结果展示、分析趋势等。通过 MATLAB 的绘图功能&#xff0c;用户可以创建各种类型的图形&#xff0c;包括线图、散点图、柱状图、曲线图等&#xff0c;以及三维图形、动画等复杂的可视…

京东云ifrit-agent占用80端口问题

即使停止服务后还是会自动重启&#xff0c;网上查找无果后询问京东云客服&#xff0c;人家服务蛮好&#xff0c;回复很快 解决办法 centos7&#xff1a; 停止服务 systemctl stop ifritd 卸载 rm -rf /usr/local/share/jcloud/ifrit centos 6: 停止服务 cd /usr/local…

Windows系统安装FinalShell

一、下载 通过百度网盘分享的文件&#xff1a;finalshell_install.exe 链接&#xff1a;https://pan.baidu.com/s/1_vcb_t-Cp4TZSN4nWUmLww 提取码&#xff1a;d6v8 二、安装 三、远程连接Linux系统 (1)打开VMware虚拟机 右键空白区域&#xff0c;点击open Terminal 输入命令…

AI/机器学习(计算机视觉/NLP)方向面试复习3

1. Pooling 有哪些方式&#xff1f;pytorch的实现&#xff1f; Pooling可以分成&#xff1a;最大池化&#xff0c;平均池化&#xff0c;全局平均池化&#xff0c;随机池化&#xff0c;空间金字塔池化。 1. 最大池化&#xff08;Max Pooling&#xff09; 最大池化是最常用的池…

YOLOv8魔改核心-模型yaml文件解析与网络结构打印

前言 本篇文章主要用于记录学习YOLOv8中网络模型yaml文件&#xff0c;我们一般只知道如何去训练模型&#xff0c;和配置yaml文件&#xff0c;但是对于yaml文件是如何输入到模型里&#xff0c;模型如何将yaml文件解析出来的确是不知道的&#xff0c;下面我们从yaml文件来讲解&a…

C语言同时在一行声明指针和整型变量

如果这么写&#xff0c; int *f, g; 并没有声明2个指针&#xff0c;编译器自己会识别&#xff0c;f是一个指针&#xff0c;g是一个整型变量&#xff1b; void CTszbView::OnDraw(CDC* pDC) {CTszbDoc* pDoc GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for nat…

Java算法之递归算法-如何计算阶乘的值

上一篇学了递归之后&#xff0c;练习一下递归算法。 题目&#xff1a;使用递归算法计算阶乘的值&#xff0c;也就是5&#xff01;5*4*3*2*1&#xff0c;直接使用循环是非常简单的&#xff0c;这边练习一下递归算法。 先写一下两个条件 基线条件&#xff1a;等于1的时候返回1…

学习C语言第十四天(指针练习)

1.第一题C 2.第二题C 3.第三题 00345 short类型解引用一次访问两个字节 4.第四题 6&#xff0c;12 5.第五题C 6.第六题 下面代码结果是0x11223300 7.第七题 int main() {int a 0;int n 0;scanf("%d %d",&a,&n);int i 0;int k 0;int sum 0;for (i 0;…

Docker 搭建Elasticsearch详细步骤

本章教程使用Docker搭建Elasticsearch环境。 一、拉取镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.8.2二、运行容器 docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-n

【Rust】所有权OwnerShip

什么是所有权 rust使用由编译器检查的一些规则构成的所有权系统来管理内存。且这不会影响程序的运行效率。 所有权规则 rust中每一个每一个值都有一个owner。在同一时刻&#xff0c;只能有一个owner。当这个owner超过范围&#xff0c;则该值会被丢弃。 String类型 为什么需…

kitti数据集转为bag

下载原始的数据集后&#xff0c;通过终端来运行&#xff1a; unzip 2011_10_03_calib.zip和 unzip 2011_10_03_drive_0047_sync.zip这样这个文件夹才算准备好&#xff1a; 然后去下载kitti2bag工具&#xff1a; pip install kitti2bag然后去2011_10_03文件夹下执行&#xf…

photoshop学习笔记——选区3 选区的变化

选区制作完成之后可以对选区进行变化 主要有&#xff1a; 反选&#xff1a;shift ctrl I 变换 修改&#xff1a; 边界 设置选区的边界大小 类似 CSS中的borderSize平滑 对选区的角进行平滑扩展 向外扩展选区收缩 向内收缩选区羽化 让边界变得过渡透明度 设置…

python安装python-bioformats库教程

在python中安装python-bioformats库,可能并不是那么顺利,需要注意一下细节问题。 过程中主要遇到以下报错信息: error: subprocess-exited-with-error python setup.py egg_info did not run successfully.│ exit code: 1╰─> [10 lines of output]Traceback (most rec…

Hello 算法:动画图解、一键运行的数据结构与算法教程

Hello 算法 《Hello 算法》是一份开源、免费的数据结构与算法入门教程&#xff0c;特别适合新手。全书采用动画图解&#xff0c;内容清晰易懂&#xff0c;学习曲线平滑&#xff0c;引导初学者探索数据结构与算法的知识地图。源代码可以一键运行&#xff0c;帮助读者通过练习提…

yolov5-7在opencv里跑自己的onnx模型

先把模型放在如下目录 运行如下代码 import cv2 import numpy as npclass Onnx_clf:def __init__(self, onnx:strdnn_model1/plane02.onnx, img_size640, classlist:list[plane]) -> None: func: 读取onnx模型,并进行目标识别para onnx:模型路径img_size:输出图片大小,和模…

智慧校园班级信息基础数据维护功能概述

在智慧校园的基础平台管理中&#xff0c;班级信息管理为所有的业务模块提供了最小单位的基础数据。它不仅是连接学生、教师与学校管理层的桥梁&#xff0c;更是优化教育资源分配、提升教学质量的催化剂。智慧校园通过融合一系列智能化工具&#xff0c;实现了对班级信息的精细化…

HarmonyOS 质量、测试、上架速浏

1.应用质量要求&#xff1a; 1. 应用体验质量建议: 功能数据完备 功能完备 数据完备 基础体验要求 基础约束 兼容性 稳定性 性能 功耗 安全…

JavaScript(17)——事件监听

什么是事件&#xff1f; 事件是在编程时系统内发生的动作或发生的事情&#xff0c;比如用户在网页上单击一个按钮 什么是事件监听&#xff1f; 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立刻调用一个函数做出响应&#xff0c;也称为绑定事件或…

扫雷小游戏纯后端版

package com.wind;import java.util.Random; import java.util.Scanner;public class ResultLei {static Random random new Random();public static void main(String[] args) {boolean end true;while (end) {System.out.println("请输入你选择的难度对应的数字&#…

MySQL大框架总结

1.DDL,DML,DQL,DCL的区别 &#xff08;由于DCL是关乎用户的&#xff0c;以下内容重点讲述数据库&#xff0c;表与数据的操作&#xff0c;所以对DCL不详细赘述&#xff09; DDL DML DQL DCL 中文/英文 数据库定义语言 data definition language 数据库操作语言 data mani…