自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

Charles Ren's Tech Blog

Everything makes you stronger and better.

  • 博客(262)
  • 收藏
  • 关注

原创 从汇编看函数调用

ESP/RSP:堆栈指针寄存器,指向栈顶。栈顶指针EBP/RBP:栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量rax:通常用于存储函数调用返回值rdi:第一个入参rsi:第二个入参rdx:第三个入参rcx:第四个入参r8:第五个入参r9:第六个入参寄存器ebp作为当前函数的“栈帧”基地址,配合一定的偏移,就可以读、写函数体的临时变量。如果一个变量是通过ebp寄存器间接访问的,那么它往往是临时变量,也叫“栈”变量。

2024-04-03 18:02:08 1024

原创 x86架构中的寄存器和常用指令

DI/EDI/RDI:目的索引寄存器,用于字符串操作中的目标地址指定。字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作。FLAGS/EFLAGS/RFLAGS:标志寄存器,包含了当前状态标志,如零标志、进位标志、溢出标志等。CX/ECX/RCX:计数寄存器,用于字符串操作和循环计数,this指针。通常用于存储函数调用返回值。DX/EDX/RDX:数据寄存器,用于 I/O 操作和一些算术运算。SI/ESI/RSI:源索引寄存器,用于字符串操作中的源地址指定。

2024-03-29 11:21:32 810

原创 浮点数的前世今生

指数可能是正数,也可能是负数,即指数是有符号的整数,而有符号整数的计算是比无符号整数麻烦的,所以为了减少不必要的麻烦,在实际存储指数的时候,需要把指数转换成无符号整数。这和无法用十进制数来表示1/3是一样的道理。但因为在32 bit 的空间中就只有2³² 种可能性,为了把所有浮点数都塞在这个32 bit 的空间里面,许多CPU 厂商发明了各种浮点数的表示方式,但若各家CPU 的格式都不一样也很麻烦,所以最后是以IEEE发布的IEEE 754作为通用的浮点数运算标准,后来的CPU 也都遵循这个标准进行设计。

2024-03-10 15:09:56 800

原创 shell脚本编译与解析

所以./bashrc文件的作用就是我们可以将要使用的全局环境变量放到这个文件中,那么我们一旦开启新的shell则自动拥有这个环境变量。shell中如果想一次执行多条命令,可以用分号隔开,多条命令的组合可以放到一个文件中,我们把它叫做脚本。shell是将错误消息与正常输出分开处理,所以如果发生错误,还是会输出到屏幕。环境变量存储在内存中,以便shell中运行的脚本和程序能够访问。子shell可以查看和使用但不能修改父shell中的全局环境变量。如果想把一个命令的输出作为另一个命令的输入,可以使用重定向。

2024-02-11 22:45:10 862

原创 MMIO&PMIO

种隐藏的接口芯片也不在少数,很多都是我们不能直观看到的。DRAM Controller View就是内存控制器能够控制的内存地址的范围,那顾名思义,内存控制器的这个控制范围主要肯定就是内存的大小范围,在内存还没有增长到今天这个范围的以前,内存控制器能够识别的大小可能只有2G,而今天它能够识别的范围远远超过之前。在早期的CPU中,CPU的位宽为32,而地址线能够达到36根(是的没错,并不是大多数人以为的32位地址线),此时限制physical address space的主要因素就是CPU的位宽了。

2024-01-29 16:49:29 884

原创 pcie基础知识

Switch: 用于拓展PCIE接口,PCIE是串行接口,所以一个PCIE接口只能接一个PCIE设备,想要多接几个PCIE设备就需要用到Switch设备,起到数据转发的作用;RC:root complex, 根桥作为cpu和pcie的媒介,是用于将一个PCIE接口拓展成多个PCIE接口,区别是RC集成在芯片内部,并且还会连接内存;pcie速率很快,pcie接口一般插显卡,也可以插无线网卡,固态硬盘,等其他硬件,以及转换成USB接口。总线标准的演进:ISA总线 -> pci总线(并行) -> pcie。

2024-01-29 10:05:14 477

原创 Linux管理与常用命令

1.点斜杠执行脚本是启动了另一个Shell去执行脚本(另一个进程),所以点斜杠执行脚本时,设置的环境变量会随着进程的退出而结束,其中的环境变量设置对当前Shell不起作用。2.点空格点斜杠执行脚本,是相当于source 执行脚本,source是执行脚本当中的命令,也就是说在当前进程中执行命令,所以其中的环境变量的设置会对当前Shell其作用。也就是说设置环境变量的时候我们使用source或者说. 空格可以直接生效。...

2023-12-28 16:21:57 526

原创 Linux查看硬件信息命令

每颗物理CPU可以有1个或者多个物理内核,通常每颗物理CPU的内核数都是固定的,单核CPU就是有1个物理内核,双核CPU就是有2个物理内核。一个物理CPU可以有1个或者多个物理内核,一个物理内核可以作为1个或者2个逻辑CPU。在Linux上cat /proc/cpuinfo,会打印每个cpu的信息。总的CPU物理内核数 = 物理CPU数 * 每颗物理CPU的内核数。其中的physical id就是每个物理CPU的id,物理CPU数就是主板上实际插入的CPU数量。

2023-10-27 17:17:11 276

原创 计算机内部总线概述

地址总线:用于传输指示计算机中的内存或外设的物理地址数据总线: 是CPU与内存或其他器件之间的数据传送的通道。控制总线:管理组件之间的信息流,指示操作是读取还是写入,并确保操作在正确的时间发生。CPU通过地址总线寻址,然后通过数据总线与外部设备互换信息。

2023-06-25 16:19:09 1895 1

原创 C专家编程 —— 运行时数据结构

当对一个可执行文件执行size命令时,比如size a.out就会打印出该文件的3个段,text, data, bss段的大小。这时将这个指针返回,我们再使用的时候,就会有问题,因为他已经被释放,所以他引用的资源可能无效也可能是其他值。而段在Intel x86模型中,表示一种设计结果,设计地址空间并非一个整体而是分成一些64K大小的区域,称为段。程序运行时系统维护一个指针,通常位于寄存器中,称为sp,用于提示堆栈当前的顶部位置。当一个函数调用另一个函数时,堆栈的状态就会如图所示,堆栈向下生长。

2023-06-24 22:23:45 667

原创 C专家编程 —— 对链接的思考

如果可执行文件只包含了文件名,让载入器在运行时才寻找所需要的函数,我们称之为动态链接。并且即使是静态链接实际上也并不是将整个库都装入到可执行文件中,而只是将所需要用到的函数装入到可执行文件。可执行文件必须能找到指定的动态链接路径,函数库不能随便移动,因为可执行文件需要定位到函数库路径。程序将在运行时去寻找函数库集合中的函数执行,而不是将他们作为自身可执行文件的一部分。如果函数库的一份副本是可执行文件的物理组成部分,我们称之为静态链接。上图比较我们可以看出静态链接和动态链接生成的可执行文件差距非常大。

2023-06-22 23:40:01 299

原创 C专家编程 —— C语言的前世今生

这里看到因为sizeof返回的是unsigned类型,在if语句中,d和TOTAL_E比较则会升级为unsigned类型,而-1则是一个非常大的数,那么这个表达式始终为假,就达不到比较的目的了。因为他在K&R C 的基础上添加了一些新的东西,并使得一些特性合法。const一般用作传参const char * 表示他指向的数据是只读的,但是这个指针是可以改变的。C语言相比B语言使用编译模式而不是解释模式,引入了类型系统,每个变量必须先声明类型再使用。而C语言就是以效率为主线,也就是编译器设计者的思想。

2023-06-21 11:17:39 434

原创 C++ 函数设计原则

重写是针对子类修改父类的虚函数,被重写的函数必须用virtual修饰。所以如果要定义需要暴露给外面,并且子类需要重写的函数则声明为public+virtual,重写的目的就是实现多态。只在本类中使用,可被继承,子类继承后也只在本类中使用的函数,声明为private。出了该类外则不能调用,既是是在其他类中调用此对象然后调用此函数也不行。只要需要对外暴露供其他类调用的函数,写为public,如果需要重写的函数则要加virtual。子类继承用的函数,直接使用,不做修改。需要子类强制实现的函数使用纯虚函数。

2023-06-01 23:13:29 103

原创 C 学习笔记 —— 内存操作函数

数组a是整型的,整型大小为4Byte,而memset函数是按照字节为单位进行赋值,取后8位,将1(00000001)赋给每一个字节。这里的结果虽然是预期的,可能是在最新版本中解决了,但是这个是不可靠的,也就是这里可能存在问题,结果不符合预期,因为memcpy不保证内存重叠部分的正确性。memmove的复制过程就好像是将src中的字节首先被复制到一个不重叠的临时数组中,然后将字节从临时数组复制到dest。将缓冲区设置为指定的字符,num是字节的个数,一个字节一个字节的改。strncmp只能比较字符串的大小;

2023-05-21 21:09:04 718

原创 C 学习笔记 —— C标准库

exit()函数用于在程序运行的过程中随时结束程序,exit的参数state将会返回给操作系统,返回0表示程序正常结束,非0表示程序非正常结束。rand()、srand()、malloc()和free()函数。exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流、关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件。atexit()函数 通过退出时注册被调用的函数提供这种功能,atexit()函数接受一个函数指针 作为参数。

2023-05-13 22:54:12 1232

原创 汇编:寄存器的寻址方式

寻址方式:在指令中得到操作数的方式,说白了也就是cpu怎么样从指令中得到操作数的方式。操作数当然就是数据。数据也就是指令的操作数有三大类,共七种寻址方式。

2023-04-08 08:35:43 1708

原创 C 学习笔记 —— 结构(二)& 内存对齐

funds2不用为字符串分配空间,因为他存储的是地址,而字符串实际占用的空间是存储在别处的。注意结构体还 不是数组,所以他的变量名和数组不一样,并不表示首元素地址。传递结构:优点,操作的是副本对原数据进行保护,缺点是传递结构浪费时间和存储空间。传递结构和传递结构地址进入函数顾名思义,就是传递结构的时候实际上传递的是结构的副本,程序使用和修改的都是副本。注意结构体一般比较大,所以对于大的结构体一般不采用在栈上分配内存,空间可能不够,而在堆上分配内存。而传递结构地址则使用的是原来的结构。

2023-04-02 12:20:57 965

原创 C 学习笔记 —— 高级指针话题

函数指针简介

2023-02-27 18:12:08 435

原创 C 学习笔记 —— 动态分配内存(malloc)

malloc会在内存池中找到一块空闲(连续)内存,返回内存块的首字节地址,所以可以把该地址赋值给一个指针,后面可以使用该指针访问这块内存。如果malloc分配内存失败,则他会返回一个空指针 NULL,我们可以通过是否为空指针来判断是否成功分配了内存,这个很重要。返回值类型是一个void类型的指针,该类型相当于一个通用指针,该指针通常被强转为一个匹配的类型并不需要考虑类型不匹配的问题,操作系统中可能原内存块无法改变大小,这是操作系统会分配一块新内存出来,新内存遵循上面两个规则,并将新指针返回。

2023-02-25 13:27:58 2053

原创 C 学习笔记 —— 声明、定义、初始化

一般的情况下,我们把建立空间的声明称之为定义,而把不需要建立存储空间的声明称之为声明。//定义 int main() {int a;//也是定义,因为建立了存储空间 extern int tern;// 声明定义在别处的变量,仅仅是声明,没有建立空间 }tern被声明了两次,第一次声明为变量预留了存储空间构成了定义。称为定义式声明。第二次声明只是使用之前的变量,而没有创建空间所以仅仅是声明。extern关键字只能做声明,不能定义。int a;

2023-02-14 23:10:26 1104 2

原创 C 学习笔记 —— 随机数函数rand()

实际上,rand() 函数产生的随机数是伪随机数,是根据一个数值按照某个公式推算出来的,这个数值我们称之为“种子”。从上面代码很容易看出,实际上这个随机种子是一个静态变量,默认是1,但是他在调用rand的时候是会被修改的。这个实例出现一个奇怪的现象,因为默认srand设置种子为1,那么我调用一次srand后面多次调用rand是否会生效呢。这样才是想要的结果。因为我们的种子每次如果是固定值,那么我们最终生成的随机数每次启动程序还是相同的。rand产生一个0-0x7fff的随机数,即最大是32767的一个数。

2023-01-29 12:30:31 1213

原创 C 学习笔记 —— 限定关键字(const、volatile、restrict、_Atomic)

智能的编译器看到上面两个变量都使用了x,而并未改变该值,所以编译器把x临时存储在寄存器。volatile 关键字修饰的变量表示可以被某些编译器,未知的因素更改,比如操作系统、硬件或者其它线程等。但是如果其他线程或者其他进程在两条语句之间修改了x的值,这时cpu就不知道该值改变还是从寄存器中读取,这读取的就是原值。所以volatile关键字表示,每次都从内存中读取值,而不做优化,不暂存在寄存器中(和register变量做区分);当一个线程对一个原子变量对象执行原子操作的时候,其他线程不能访问该对象。

2023-01-27 22:07:24 647

原创 C 学习笔记 —— 存储类别

一般的情况下,我们把建立空间的声明称之为定义,而把不需要建立存储空间的声明称之为声明。变量的初始化,就很简单了,为变量声明或者定义之后,赋上初值的过程,就是变量的初始化。tern被声明了两次,第一次声明为变量预留了存储空间构成了定义。称为定义式声明。第二次声明只是使用之前的变量,而没有创建空间所以仅仅是声明。int a;只是定义并没有付初始值,所以不是初始化。int a = 4既是定义又是初始化。仅仅是声明。extern关键字只能做声明,不能定义。当然定义和初始化也可以分开int b;

2023-01-19 19:17:54 820 2

原创 C 学习笔记 —— typedef & 二进制输出

如果声明总位数超过unsigned int类型大小,就会用到下一个unsigned int类型的存储位置。C语言以 unsigned int作为位字段的基本布局单元,即使一个结构中只有一个成员1位字段,该结构也是unsigned int类型的大小。结构体变量prnt被存储在int大小的内存单元中,他只占其中的4位。位字段是一个signed int或者unsigned int类型变量中一组相邻的位。所以我们想直观看到二进制数我们可以将整数转换成对应进制的字符串。输出十六进制:%x;

2023-01-09 10:51:19 457

原创 《深入理解计算机系统》学习笔记 —— 虚拟内存详解

第二,只有一级页表存储在主存中,而二级页表可以放到硬盘中,经常需要使用的缓存在主存中。如果我们的虚拟地址空间为32位,也就是可以表示4G的虚拟内存,把这个4G内存分为很多个页,假设每个页大小为4K,那么就会分成1M个页,那么我们使用页表所需要的PTE数量也就需要是1M个。当CPU要读取虚拟内存中的一个字节的数据时,如果页命中,说明VP缓存在DRAM中,CPU拿到虚拟地址,通过MMU转换器得到定位页表中某个PTE的位置,然后通过获取PTE中的数据得到VP是在DRAM中,然后就可以得到该物理地址指向的页帧。

2022-12-28 19:27:22 1766 2

原创 指令集,ISA, x86,x86_64, AMD64等名词解析

指令集架构(Instruction Set Architecture, ISA)首次出现在IBM的System/360中。作为软硬件之间的接口,ISA在编译器编写者和处理器设计者之间提供了一个抽象层,将编程所需要了解的硬件信息从硬件系统中抽象出来。这样软件开发者就可以面向ISA编程了,开发出来的软件不经过修改就可以在符合该ISA的计算机上运行了。ISA定义了机器语言程序编写者需要知道的一切,这其中就包括指令集,指令集编码,基本数据类型,寄存器,寻址模式,存储体系,异常处理,中断,I/O模型等。

2022-12-08 17:32:55 1510

原创 C 学习笔记 —— 宏

4*84*8这两个宏定义是不同的,一个是带空格的,而另一个不带空格。空格也是宏定义中的一部分。2020可以重定义宏,但是重定义的值必须和原值相同。如果不同,则有些编译器会报错,有些会给出警告。移除LIMIT定义后,就可以给LIMIT重新定义成一个新值。如果没有定义LIMIT,取消定义一样有效。看上去像函数调用,但是和函数调用完全不同。看下面实例int z;}(int z;})int z;}*int z;

2022-10-29 17:35:51 900

原创 vscode ssh远程连接失败问题及解决

如果 VSCode 软件有更新,则会自动去下载对应版本的 vscode-server 软件,此时如果我们的 VSCode 有更新多个版本的话,就会在上述目录看到不同的 HASH 版本。当我们使用 Remote 连接到远程服务器时,在服务器会有一个 .vscode-server 的隐藏目录,该目录的作用,就是存放不同 VSCode 版本的远程连接信息。把上面连接的替换成 提交的最长的一串号,比如这个版本就得到下面的连接。一般是更新了vscode版本之后出现的,报错的种类有很多,

2022-10-01 14:44:27 35905 14

原创 C 学习笔记 —— 位操作与位运算

单独操控位,有时向硬件设备发送一两个字节来控制这些设备,其中每个位都有特定含义。一个字节:从左到右8位编号分别为7~0。编号7被称为高位,编号0被称为低位。一字节有8bit,2的8次方256个值。通常无符号1byte能表示的数范围是0~255.有符号表示范围-128 —— +127。

2022-09-18 17:59:15 916

原创 C 学习笔记 —— 字符串

字符串是以空字符\0结尾的char类型数组字符串常量char类型数组指向char的指针定义字符串数组,也可以使用上述两种方式。指针方式:效率更高,因为不用存储字符串副本,但是不能修改原字符串。(绝大多数字符串操作由指针完成)数组方式:效率低,但是可以修改字符串。

2022-09-04 11:14:15 764

原创 Vim使用手册

如果你想要删除指定范围的行,比如从第 3 行到第 5 行,按 ESC,然后输入“:3,5d”,回车后就可以删除了;删除当前行之前的所有行:按下 ESC 后,输入“:1,.-1d”,回车后即可;删除当前行之后的所有行:按下 ESC 后,输入“:+1,$d”,回车后即可;按n搜索下一个匹配,按Shift+n搜索上一个。注意这会删除包括1200和1205行内容。搜索指定关键字:/key 然后回车。4dd, 删除包括当前行后4行。删除单行:光标位置:dd。v选定指定块,然后d删除。......

2022-08-14 13:18:05 1004

原创 C 学习笔记 —— 联合&位段&枚举

/定义一个fit变量unionholdsave[10];//顶一个save数组unionhold*pu;//指针定义变量,编译器会分配足够的空间,这里union的三个成员最大的是double,8字节,所以编译器会给fit分配8字节内存。创建一个数组,内含10个元素,每个元素都是union类型并占8字节大小。该指针变量存储一个hold类型地址。...

2022-07-31 18:39:19 285

原创 C 学习笔记 —— 结构(一)

这里出现问题是因为std1给std2赋值的时候,因为结构体中存在指针,赋值只把结构体中指针指向的地址给拷贝过去了,所以当我们释放结构体std2时,因为std1里的char*已经释放了,但是我们又释放了这个地址,所以重复释放报错。但是如果一个结构体包含指针变量,并在使用结构的过程中进行了动态内存的分配,同时进行了相同类型的结构体的变量之间进行了相互赋值,此时会引发浅拷贝和深拷贝问题。传递结构和传递结构地址进入函数顾名思义,就是传递结构的时候实际上传递的是结构的副本,程序使用和修改的都是副本。......

2022-07-30 21:22:57 364

原创 《深入理解计算机系统》学习笔记 —— 2.1信息的存储

幸好,除了二进制,还有人们生活中常用的十进制和八进制、十六进制,其中,十进制是我们最熟悉的,十六进制是程序员很喜欢的,为什么呢,因为相同的数据,十六进制的表示方法最短嘛!十进制是我们最熟悉的,但是他和二进制的转换并不方便。二进制很好,计算机很喜欢,但随之而来又有一个问题,二进制0和1表示的数据,程序员读起来实在是不方便,比如10111110000101。因为当进制越大,需要的表示数字的东西就越多,比如二进制只需要0和1,十六进制却需要1到9数字和几个字母,这就需要一种权衡了。是0的就表示false。....

2022-07-22 11:12:39 398

原创 C 学习笔记 —— 指针

指针是一个值为内存地址的变量。类比一下int类型变量的值是个整数。指针类型变量的值是个地址。inta=4;//变量a是一个整数值int*p=0x3434523;//变量p是一个地址值但是这个地址的值一般我们肯定不能显示的知道,一般交给系统分配完之后,然后我们使用inta=4;//因为系统已经给变量a分配地址了,所以我们可以取到a的地址然后赋值给p这里指针是p,我们也可以说是指针p指向变量a。.........

2022-07-20 23:44:53 578

原创 C 学习笔记 —— 数组和指针

数组和指针的关系非常紧密,所以这本书将他们放到一章来学习。下面我们一起来看一下。指针的值是他所指向对象的内存地址。指针前面使用*运算符可以得到指针所指向的对象的值。指针+1,是他对应存储单元+1.......

2022-07-17 21:59:33 412

原创 C 学习笔记 —— 文件

https://blog.csdn.net/colourful_sky/article/details/80334250所有文件内容都以二进制(0/1)存储。C语言把文件看作一系列连续字节,每个字节都能被单独读取。与Unix的文件结构对应。有两种文件形式,文本文件和二进制文件。计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。二进制或者文本与文件的格式并没有任何关系,而是文件流操作时对数据的表达方式不同。读取单位:如果文件最初使用

2022-07-11 20:09:01 446

原创 一级页表与二级页表

用户空间:分为5个不同内存区域:代码段:只读,存放可执行文件的操作指令;镜像;数据段:存放可执行文件中已初始化全局变量;存放静态变量和全局变量;BSS段:未初始化全局变量堆:存放被动态分配的内存段;栈:存放临时创建的局部变量;段是信息的逻辑单位并没有写入真正的内存,根据用户的需要划分,段对用户是可见的; 页时信息的物理单位,为管理内存方便和划分的,对用户透明的。首先我们看地址,一个32位地址是4byte,十六进制表示0x12345678。每个地址里面存1byte数据,那么他可以存4G的数据,也

2022-07-09 10:10:25 15866 17

原创 C 学习笔记 —— 字符

上一章介绍的printf和scanf函数都属于IO函数。这里我们介绍两个函数getchar()和putchar()用于字符的IO。getchar()函数不带任何参数,如果缓冲区为空,则会等待缓冲区,当输入并回车后,将从输入队列中返回下一个字符。putchar()函数打印输入的参数。getchar()函数把每个字符解释称一个字符编码,而scanf()函数以同样的方式看待输入也是读取字符,但是他会把字符输入根据转换说明转成相应的数值。比如:如果我在键盘输入然后回车,那么打印将是a。因为getchar(

2022-06-24 08:50:49 311

原创 C 学习笔记 —— IO(输入/输出)

明示常量又叫符号常量,define修饰的字符#define TAX 0.15在编译程序时就会将TAX都替换成0.15。在运行程序前所有的替换已经完成。作用:提高程序的可读性和可维护性。const修饰的是变量,但是是只读的。他是运行期才分配内存。存储位置和常量也不同。转换说明把以二进制格式存储在计算机中的值,转换成字符串便于显示。比如76这个值,他在计算机中就是01001100。使用%d的意识是“把给定的值翻译成十进制文本并打印出来”。所以%d将其转换成字符7和6并显示为76。printf打印不

2022-06-19 16:21:07 674

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除