热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c语言怎么访问64位地址_C语言调动硬件的原理是什么?

大家都知道我们可以使用C语言写一段程序来控制硬件工作,但你知道其工作原理吗?1c语言在实际运行中,都是以汇编指令的方式运行的,由编译器把C
7ca2c4415f7fa958423ba4811fbb37af.png


大家都知道我们可以使用C语言写一段程序来控制硬件工作,但你知道其工作原理吗?
1
c语言在实际运行中,都是以汇编指令的方式运行的,由编译器把C语言编译成汇编指令,CPU直接执行汇编指令。
所以这个问题就变成,汇编指令是如何操作硬件的?
如果把硬件平台限制在x86环境下,那么汇编指令操作硬件基本上只有两种方式:
方式一:
通过向内存空间写数据。硬件会把硬件上的各种寄存器(外行可以理解为访问硬件的接口或者操作硬件的工具)映射到某一块内存地址空间上,之后只要用汇编指令,甚至C语言去读写这一段内存地址空间(并非真正操作物理内存),就可以达到操作硬件的目的了。
如果题主还有WindowsXP环境(虚拟机也可以),就可以用汇编指令直接操作显存:
MOV AX,B800
MOV ES,AX
XOR DI,DI
MOV CX,0800
MOV AX,5555
REPZ STOSB
硬件的各种寄存器会被映射到某一块物理内存中,这种方式称为MMIO,在Windows的设备管理器里,右键点设备,看属性-》资源里,不少硬件设备都有“内存范围”的参数,这里的内存范围就表示这个硬件的资源可以通过访问这一段内存来控制它。
方式二:
x86汇编中,还有两个特殊的指令是IN和OUT,这是x86平台独有的,上面图里的I/O范围,就是用IN/OUT这两个指令来访问和控制的。
以上两种访问硬件的方式,第一种是可以用C语言实现的,上面一段汇编,本质上类似于C语言代码:
char ptr = 0xB8000;
int i;
for (i = 0; i 《0x800; i++)
{ptr + i = 0x55;
}
第二种IN/OUT方式没有直接的C语言语法对应,需要自己封装汇编。
那么为什么平时很难用C语言操作硬件呢?这是因为平时写的代码大多数都在保护模式下,保护模式下,直接访问物理地址会受到限制,C语言操作的地址都是虚地址。
对于Windows来说,要访问物理地址,需要工作在内核模式,也就是的写驱动才行。
而在显存方面,首先,题主要先明白物理地址和虚拟地址的概念。
原来的8086cpu设计的时候,地址空间有一块区域(640K-1M)之间,有一块作为显存使用
这里你说的预留的地址,是指物理地址,这一段地址的准确范围是000A0000-000BFFFF,不管是32位还是64位CPU,这一段物理内存地址一直都保留给显存使用,不区分32位还是64位,也不区分保护模式还是实模式。
可见这一段内存至今仍然是留给显卡使用的。
那么现在为什么不能直接用这段内存了?
因为现在的软件都运行在保护模式下,访问的地址都是虚拟地址,而并非物理地址,包括你使用cmd命令打开的环境,都是虚拟地址,虽然32位XP里能用debug命令向000B8000上写数据并能显示在cmd的界面里,但本质上,这都是虚拟出来的。
如果要想用这段显存怎么办?
自己写一个简易的操作系统,不启动显卡的各种图形加速功能,CPU进入保护模式后在GDT里映射一个4G的数据段,与物理地址一致,那么向000B8000上写数据,就会像过去DOS一样显示在屏幕上,所以保护模式下也可以访问这一段内存。所以,保护模式下,也可以用它。
显卡那么多显存是怎么映射的?
有很多内存地址被映射给显存了,就是通过这种映射关系,把一些物理地址留给显存,使得CPU能像访问内存一样访问显存资源。
当然,实际情况是,2G显存未必完全映射,而是只映射一部分地址,显卡有一些开放的寄存器能够控制哪部分显存映射过来,这样就能使得CPU在使用比较少的物理地址范围的情况下,访问全部的显存。
还有一个很有意思的事情:在虚拟机里,找到映射的高地址部分的第一块内存区域,写一个能直接访问物理地址的程序(比如一个驱动),去读这一块内存,然后写到文件里,再用屏幕截图,也写到文件里,会发现截图的内容和显存里读出来的内容基本上是一样的。
2
1 语言层面上,C能直接操作的“硬件”只有内存地址。虽然C支持register关键字,但是不能指定某个特定的寄存器,所以只有内存地址。而C中操作内存地址的方式就是指针。例如:
char p = 。..;p = 。..;
2 根据1反推,可以明白如果要开放给C来操作某个硬件,最直接的方案就是设计硬件的时候预先分配好一些固定的地址的用途,然后实际项目中往这些固定地址写入合法的数据。这样就可以通过类似
uint32_t p = SCREEN_ADDR;p = RGBA(0xff,0xff,0xff,0xff);
这样的代码来实现对硬件的操作了。
3 那这个地址怎么拿到呢?什么样的数据才是合法的呢?要解答这些问题,就需要查阅具体设备的spec了。例如这个一眼看过去就能的明白的例子(一眼没看明白请反复阅读以完全理解上面第二点内容):
我们是用电脑的键盘来输入的指令,每一个指令都对应一个ASCII码,而这里的ASCII码就是有序的电压的高低(或电流的有无,下面只提电压的高低),即我们输入的是电压的高低,你所看到代码是这些电压的高低控制显示器所显示的图像,其实电脑也不知道它是什么,只知道这样显示。
结论:代码其实就是存储在存储器(内存、硬盘或者闪存等等)中有序的电压的高低。
再说编译:
编译是一个有序的电压的高低向另一种有序的电压高低的一种转换过程,下面以52单片机为例,我们编译是从表示ASCII码的那种有序电压高低转换为52单片机能够识别的另一种规定好的有序电压高低,即表示HEX文件的电压高低。
结论:编译出的结果还是电脑中存储的有序电压高低。
到单片机烧录:
接下俩就是烧录,理解了上面两点就很容易理解下面的内容,烧录就是电脑中的有序电压高低通过数据线传输到单片机中的ROM中。
接下来ROM就可以释放其中的电压来控制外围的电路。
总结:从代码的编辑到最后对电路的控制都是电压在起作用,只是为了方面我们而给我们展现的形式不一样而已,而其本质都是电压,这样也就不存在转换。
理解这句话:世界上没有软件,软件只是对硬件的一种反映,就像意识是对世界的一种反映是一样的!
相信这样就很容易理解了。学习从来不是一个人的事情,要有个相互监督的伙伴,工作需要学习C/C++或者为了入行、转行学习C/C++的伙伴可以私信回复小编“学习”领取全套免费C/C++学习资料、视频教程内容包括
1.开发环境搭建
2.C语言教程
3.C++教程
4.数据结构与算法
5..Net全套教程
6.C++Primer教程
7.项目实操



推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • CMake跨平台开发实践
    本文介绍如何使用CMake支持不同平台的代码编译。通过一个简单的示例,我们将展示如何编写CMakeLists.txt以适应Linux和Windows平台,并实现跨平台的函数调用。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 本文详细介绍了如何在Ubuntu系统中下载适用于Intel处理器的64位版本,涵盖了不同Linux发行版对64位架构的不同命名方式,并提供了具体的下载链接和步骤。 ... [详细]
author-avatar
手机用户2502887703
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有