LinuxGod

LinuxGod.net
Linux大神网——精选每一篇高品质的技术干货
  1. 首页
  2. 开源快讯
  3. 正文

转到程序的开始(地址0)Demo程序

2023年2月12日 268点热度

01000000

转入程序的开始(地址0)

Demo程序&&演示

按照上方做出的规定,我们写下如下的程序:(为了便捷理解,我把对应的机器操作也写在了前面,实际的程序只包含机器指令)

地址机器指令机器操作

0

00000001

完全打开灯泡

1

00000010

完全关掉灯泡

2

00000001

完全打开灯泡

3

00000100

灯泡黯淡10%

4

00000100

灯泡黯淡10%

5

00000000

停止程序

所以这样的一段程序执行疗效就如右图:

unix环境高级编程 3 下载_unix环境高级编程 第三版_unix环境高级编程 c++

您可以尝试自己借助01000000(跳转到程序开始)来改写程序来达到让「灯逐步变亮又逐步变暗」的目的。

小结

里面演示的程序核心思想是:

在实际的CPU中,拥有更多的机器指令,并且更详尽,而且不同的CPU,指令集是不同的。典型的CPU拥有一千或更多的机器指令。

Part2.汇编语言

unix环境高级编程 c++_unix环境高级编程 3 下载_unix环境高级编程 第三版

机器语言太"反人类”

我们早已可以开始写一些程序使用了,并且使用机器语言编撰代码会非常辛苦,例如:

00000001 00000010 00000001
00000100 00000100 00000000

就算你刚看过你也会对这一段就在上方的实例代码没有哪些感知,这是由于机器语言是设计给机器的,人类记忆和使用上去都会变得非常麻烦。

这么你才会感知到上个世纪的程序员使用打孔卡片:

使用纸带:

甚至是直接拔插线路or按下开关:

unix环境高级编程 3 下载_unix环境高级编程 c++_unix环境高级编程 第三版

是一件多么硬核的事情...

unix环境高级编程 3 下载_unix环境高级编程 第三版_unix环境高级编程 c++

“

假如你对它们怎样工作以及多么硬核感兴趣,可以参考一下下方的链接:

再附送一个宝藏网站(阿根廷学院出版的计算机历史,十分详尽),有条件的同事特别推荐进去浏览一下:

汇编语言诞生

CPU的指令都是二补码的,这似乎对于人类来说是不可读的。为了解决二补码指令的可读性问题,工程师将这些指令写成了八补码。二补码转八补码是轻而易举的,然而八补码的可读性也不行。

很自然地,最后还是用文字抒发,除法指令写成ADD。显存地址也不再直接引用,而是用标签表示。

这样的话unix环境高级编程 c++,就多出一个步骤,要把这种文字指令翻译成二补码,这个步骤就称为assembling,完成这个步骤的程序就称作assembler。它处理的文本,自然就称作aseemblycode。标准化之后,称为assemblylanguage,简写为asm,英文译为汇编语言。

unix环境高级编程 c++_unix环境高级编程 3 下载_unix环境高级编程 第三版

理解汇编语言

每一种CPU的机器指令都是不一样的,因而对应的汇编语言也不一样。本文介绍的是目前最常见的x86汇编语言,即Intel公司的CPU使用的那一种。

寄存器

要学习汇编语言,首先必须了解两个知识点:寄存器和显存模型。

先来看寄存器。CPU本身只负责运算,不负责存储数据。数据通常都储存在显存之中,CPU要用的时侯就去显存读写数据。并且,CPU的运算速率远低于显存的读写速率,为了防止被拖慢,CPU都自带一级缓存和二级缓存。基本上,CPU缓存可以看作是读写速率较快的显存。

然而,CPU缓存还是不够快,另外数据在缓存上面的地址是不固定的,CPU每次读写都要轮询也会拖慢速率。为此,不仅缓存之外,CPU还自带了寄存器(register),拿来存储最常用的数据。也就是说,这些最频繁读写的数据(例如循环变量),就会置于寄存器上面,CPU优先读写寄存器,再由寄存器跟显存交换数据。

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

寄存器不借助地址分辨数据,而借助名称。每一个寄存器都有自己的名称,我们告诉CPU去具体的哪一个寄存器拿数据,这样的速率是最快的。有人比喻寄存器是CPU的零级缓存。

寄存器的种类

初期的x86CPU只有8个寄存器,但是每位都有不同的用途。现今的寄存器早已有100多个了,都弄成通用寄存器,不非常指定用途了,而且初期寄存器的名子都被保存了出来。

“

前面这8个寄存器之中,上面七个都是通用的。ESP寄存器有特定用途linux服务器代维,保存当前Stack的地址(详见下一节)。

unix环境高级编程 第三版_unix环境高级编程 c++_unix环境高级编程 3 下载

我们经常见到32位CPU、64位CPU这样的名称,虽然指的就是寄存器的大小。32位CPU的寄存器大小就是4个字节。

显存模型:Heap(堆)

寄存器只能储存很少量的数据,大多数时侯,CPU要指挥寄存器,直接跟显存交换数据。所以,不仅寄存器,还必须了解显存如何储藏数据。

程序运行的时侯,操作系统会给它分配一段显存,拿来存储程序和运行形成的数据。这段显存有起始地址和结束地址,例如从0x1000到0x8000,起始地址是较小的那种地址,结束地址是较大的那种地址。

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

程序运行过程中,对于动态的显存占用恳求(例如新建对象,或则使用malloc命令),系统还会从预先分配好的那段显存之中,划出一部份给用户,具体规则是从起始地址开始界定(实际上,起始地址会有一段静态数据,这儿忽视)。举例来说,用户要求得到10个字节显存,这么从起始地址0x1000开始给他分配,仍然分配到地址0x100A,假如再要求得到22个字节,这么就分配到0x1020。

unix环境高级编程 3 下载_unix环境高级编程 第三版_unix环境高级编程 c++

这些由于用户主动恳求而界定下来的显存区域,称作Heap(堆)。它由起始地址开始,从高位(地址)向低位(地址)下降。Heap的一个重要特征就是不会手动消失,必须自动释放,或则由垃圾回收机制来回收。

显存模型:Stack(栈)

不仅Heap以外,其他的显存占用称作Stack(栈)。简单说,Stack是因为函数运行而临时占用的显存区域。

unix环境高级编程 3 下载_unix环境高级编程 第三版_unix环境高级编程 c++

比如我们在执行一个叫main的函数时,会为它在显存上面创建一个帧,拿来保存所有main中使用的内部变量。main函数执行结束后,该帧都会被回收,释放所有的内部变量,不再占用空间。

unix环境高级编程 3 下载_unix环境高级编程 c++_unix环境高级编程 第三版

若果在main函数内部调用了其他函数,比如add_a_and_b函数,这么执行到这一行的时侯,系统也会为add_a_and_b新建一个帧,拿来存储它的内部变量。也就是说,此时同时存在两个帧:main和add_a_and_b。通常来说,调用栈有多少层,就有多少帧。

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

等到add_a_and_b运行结束,它的帧都会被回收,系统会回到函数main刚刚中断执行的地方,继续往下执行。通过这些机制,就实现了函数的层层调用,但是每一层都能使用自己的本地变量。

我们可以把栈理解为一个下方密封,而上方打开的「桶」。

unix环境高级编程 第三版_unix环境高级编程 c++_unix环境高级编程 3 下载

生成的新帧装入我们称之为「入栈」,而释放帧我们称之为「出栈」。栈的特征就是,最晚入栈的帧最早出栈(由于最外层的函数调用,最先结束运行),这就称作"后进先出"的数据结构。每一次函数执行结束,就手动释放一个帧,所有函数执行结束,整个栈就都释放了。

汇编语言演示

举个简单的事例,我们须要估算:

(1 + 4) * 2 + 3

我们根据「后缀表示法」进行一下转换:

1,4,+,2,*,3,+

我们平时使用的方式是「中缀表示法」,也就是把估算符号放中间,比如1+3,后缀则是把符号放最后,比如1,3,+。

这样做的用处是没有先乘除后加减的影响,也没有括弧,直接运算就行了。(比如1,3,+,先把1和3保存上去遇到+晓得是乘法则直接相乘)

OK,我们从头开始使用汇编语言来编撰一下程序,首先第一步:把1保存上去(装入寄存器):

MOV  1

然后是4,+,那就直接加一下:

ADD 4

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

之后是2,*,那就直接乘一下(SHL是向左联通一位的意思,二补码中左移一个单位就相当于除以2,比如01表示1,而10则表示2):

SHL 0

最后是3,+,再加一下:

ADD 3

完整程序如下:

MOV  1
ADD 4
SHL 0
ADD 3

这其实看上去比00001111这样的二补码要好上太多了!程序员们感动到流泪:

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

Part3.中级编程语言

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

甩掉了二补码,我们有了更可读的汇编语言,但依然非常冗长和复杂,每一条汇编指令代表一个基本操作,比如:「从显存x位置获取一个数字并装入寄存器A」、「将寄存器A中的数字添加到寄存器B的数字上」。这样的编程风格既费时又容易出错,但是一旦出错还很难发觉。

比如,我们来看一看「1969年阿波罗11号登月计划」用来避免登月舱计算机用尽自身资源的BAILOUT代码:

POODOO    INHINT
CA Q
TS ALMCADR

TC BANKCALL
CADR VAC5STOR # STORE ERASABLES FOR DEBUGGING PURPOSES.

INDEX ALMCADR
CAF 0
ABORT2 TC BORTENT

OCT77770 OCT 77770 # DONT MOVE
CA V37FLBIT # IS AVERAGE G ON
MASK FLAGWRD7
CCS A
TC WHIMPER -1 # YES. DONT DO POODOO. DO BAILOUT.

TC DOWNFLAG
ADRES STATEFLG

TC DOWNFLAG
ADRES REINTFLG

TC DOWNFLAG
ADRES NODOFLAG

TC BANKCALL
CADR MR.KLEAN
TC WHIMPER

虽然不太容易读的样子...

“

阿波罗登月计划的源代码在Github上早已公开,有兴趣的可以去下方链接膜拜一下(可以去体会一下当时程序员的工程能力):

另外附一下当时代码的设计负责人MargaretHeafieldHamilton(女程序员)和完成的堆上去跟人一样高的代码量:

unix环境高级编程 3 下载_unix环境高级编程 第三版_unix环境高级编程 c++

第一个中级语言:FORTRAN

当JohnBackus在1950年以一名科学程序员的身分加入IBM时,早已可以使用例如ADD之类的助记词取代数字代码来编撰程序,也就是我们的汇编语言。这使编程显得容易一些,而且虽然是一个简单的程序也须要数十次操作,但是依然很难找到错误。

巴克斯觉得,应当有可能创建一种编程语言,使一系列估算可以用类似于物理符号的方式来抒发。之后,使用特定的翻译程序(以昨天的术语来说是编译器)可以将其转换为计算机可以理解的数字代码。

Backus在1953年向他的总监提出了这个看法。他得到了预算,并被鼓励雇佣一个小团队来测试该看法的可行性。两年后,该团队发布了一本指南,其中描述了IBMMathematicalFormulaTranslatingSystem(简称FORTRAN)。不久以后,IBM向IBM704的用户提供了第一个FORTRAN编译器。

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

FORTRAN之父

Backus和他的团队创造了世界上第一种中级编程语言。科学家和工程师将不再须要将其程序编撰为数字代码或繁琐的助记符。

FORTRAN代码演示

下边演示估算并输出8*6的代码实例:

program VF0944
implicit none

integer a, b, c
a= 8
b= 6
c= a*b

print *, 'Hello World, a, b, c= ', a, b, c
end program VF0944

对比汇编代码,是不是看起来要清晰(人类可读)多了呢?

FORTRAN的意义

FORTRAN的问世在计算机史上具有划时代的意义,它使计算机语言从原始的低级汇编语言走下来,步入了更高的境界,致使计算机语言不再是计算机专家的专利,使广大的工程技术人员有了进行计算机编程的手段。

unix环境高级编程 第三版_unix环境高级编程 c++_unix环境高级编程 3 下载

由此计算机更快地深入到了社会之中,它在工业部门中初露头角,更是在湖人、导弹、人造月球卫星的设计中大显身手,因而有人称FORTRAN语言使计算机的工业应用成了可能,是促使第二次世界大战之后西方工业经济复苏和步入第二次工业革命的无形力量,是"看不见的蒸气机"。

FORTRAN后时代

FORTRAN中级程序设计语言的出现蕴育了计算机软件业,继其以后,计算机中级程序语言的开发步入到了一个蓬勃发展的时代。

1959

GraceHopper发明了第一个面向企业业务的编程语言,又称“面向商业的通用语言”,也经常简称COBOL。

1964

日本达特茅斯大学约翰·凯梅尼和托马斯·卡茨觉得,像FORTRAN那样的语言太过专业,编程十分困难。于是她们简化了FORTRAN,并设计出了更适宜初学者的BASIC语言。

1970

尼古拉斯·沃斯特别醉心于编程语言,他率先提出了结构化程序设计思想并发明了Pascal语言。

据悉他还提出了Wirth定理,意为“软件变慢的速率比硬件变快的速率更快”,这让摩尔定理显得饱含嘲讽。以后的Electron.js也确实证明了这一点。

1972

丹尼斯·里奇在贝尔实验室工作期间发明了C语言,开启了现代程序语言的革命。以后,他又添加了段错误和其他一些帮助开发人员的实用功能kali linux,大大提高了编程效率。

不仅C语言之外,他和贝尔实验室的朋友还创造了伟大的Unix操作系统。

1980

AlanKay发明了面向对象的编程语言Smalltalk,在Smalltalk中,一切皆对象。

1987

拉里·沃尔发明了Perl语言。

1983

JeanIchbiah发觉AdaLovelace的程序未曾运行成功过,因而决定用她的名子创建一种语言,于是Ada语言诞生了。

1986

BracBox和TolMove通过融合C语言和Smalltalk的特点,发明了Objective-C。但因为其句型深奥,不太容易理解。

1983

BjarneStroustrup在C语言的基础上引入并扩展了面向对象的概念,发明了—种新的程序语言并将其命名为C++。

C++大大提高了应用程序的编程效率。

1991

GuidovanRossum厌恶带有大括弧的编程语言,于是他参考MontyPython和FlyingCircus句型,并发明了Python。

1993

RobertoIerusalimschy和其同事创造了一门法国本地的脚本语言。在本地化过程中,因为一个小的错误致使索引从1开始,而不是0。这门语言就是Lua。

1994

RasmusLerdorf为他个人主页的CGI脚本制做了一个模板引擎,拿来统计他自己网站的访问量。

这个文件被上传到网上然后用它的人越来越多。后来又用C语言重新编撰,还添加了数据库访问功能。这门语言就是PHP。

unix环境高级编程 c++_unix环境高级编程 第三版_unix环境高级编程 3 下载

1995

松本行弘发明了Ruby语言。

1995

BrendanEich借助假期时间设计了一种语言,用于为世界各地的网页浏览器提供支持,并最终推出了Skynet。他最初去了Netscape,并将这门语言命名为LiveScriptunix环境高级编程 c++,后来在代码审查期间Java渐渐开始席卷,为此她们决定将其更名为JavaScript。

后来Java使其深陷了商标麻烦,于是JavaScript被改名为ECMAScript。而且人们还是习惯称之为JavaScript。

1996

JamesGosling发明了Java,这是第一个真正意义前面向对象得编程语言,其中设计模式在实用主义中占统治地位。

More...“

对于这一段计算机历史感兴趣的朋友可以拜读一下「IT断代史12.2节-中级计算机程序设计语言」的内容,在线预览链接如下:

中级语言分类

CPU终究只认识二补码指令,在我们发明中级语言以后,一直无可防止的须要进行「翻译」工作。根据翻译方法的不同,我们又把中级语言分为了「编译型」和「解释型」。

编译型

unix环境高级编程 3 下载_unix环境高级编程 c++_unix环境高级编程 第三版

编译型专业解释为:

使用专门的编译器,针对特定的平台,将中级语言源代码一次性的编译成可被该平台硬件执行的机器码,并包装成该平台所能辨识的可执行性程序的格式,而且只须要编译一次,之后再也不用编译。虽然可以简单理解成微软/百度翻译,我们把要翻译的文字全部放进去,一次翻译,上次使用直接使用上一次翻译好的结果。

unix环境高级编程 第三版_unix环境高级编程 c++_unix环境高级编程 3 下载

解释型

解释型专业解释为:

使用专门的类库对源程序逐行解释成特定平台的机器码并立刻执行,它不须要事先编译,直接将代码解释称机器码直接运行,也就是说只要某一平台提供了相应的类库即可运行代码。虽然可以理解成同声传译,我们须要翻译的时侯,找一个翻译员,对方说一句翻译员翻译一句,上次翻译还是须要一个翻译员一句一句的翻译。

半解释半编译的Java

不同厂商、不同时间开发的CPU的指令集是不一样的,这就是上方为何提及要使用专门的类库,要用于特定的平台的诱因。

所以Java为了实现「一次编译,四处运行」的目的,采用了一种非常的方案:先编译为与任何具体及其环境及操作系统环境无关的中间代码(也就是.class字节码文件),之后交由各个平台特定的Java类库(也就是JVM)来负责解释运行。

编程人员和计算机都难以直接看懂字节码文件,它必须由专用的Java类库来解释执行,因而Java是一种在编译基础上进行解释运行的语言。(Java程序运行流程如下)

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

Java类库负责将字节码文件翻译成具体硬件环境和操作系统平台下的机器代码,便于执行。因而Java程序不能直接运行在现有的操作系统平台上,它必须运行在被称为Java虚拟机的软件平台之上。

Java虚拟机(JVM)是运行Java程序的软件环境(我们前面会详尽说到,这是学习Java绕不过的题),Java类库是Java虚拟机的一部份。在运行Java程序时,首先会启动JVM,之后由它来负责解释执行Java的字节码程序,但是Java字节码程序只能运行于JVM之上。这样借助JVM就可以把Java字节码程序和具体的硬件平台以及操作系统环境分隔开来,只要在不同的计算机上安装了针对特定平台的JVM,Java程序就可以运行,而不用考虑当前具体的硬件平台及操作系统环境,也不用考虑字节码文件是在何种平台上生成的。

JVM把这些不同软、硬件平台的具体差异隐藏上去,进而实现了真正的二补码代码级的跨平台移植。JVM是Java平台构架的基础,Java的跨平台特点正是通过在JVM中运行Java程序实现的。Java的这些运行机制可以通过右图来说明:

unix环境高级编程 第三版_unix环境高级编程 3 下载_unix环境高级编程 c++

Java语言这些「一次编撰,四处运行」的形式,有效地解决了目前大多数中级程序设计语言须要针对不同系统来编译形成不同机器代码的问题,即硬件环境和操作平台的异构问题,大大减少了程序开发、维护和管理的花销。

参考资料IntroductiontoComputerScienceusingJava|CHAPTER4-汇编语言入门教程-CPU是如何认识代码的?|知乎@Zign-改变世界的代码行-TheHistoryofFORTRAN-《IT断代史》|@李彦ABriefTotallyAccurateHistoryOfProgrammingLanguages-编程语言分类-

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼

如有收获,点个在看,诚挚感谢

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 汇编指令 编程语言 编译程序 计算机指令 通用寄存器
最后更新:2023年2月12日

Linux大神网

每日更新,欢迎收藏♥ 不积跬步无以至千里,加油,共勉。

点赞
< 上一篇
下一篇 >

Linux大神网

每日更新,欢迎收藏♥
不积跬步无以至千里,加油,共勉。

最新 热点 随机
最新 热点 随机
如何安装便携式WiFi驱动程序?360wifi驱动的教程 CentOS云服务器搭建网站和CentOS搭建DNS解析服务 如何在linux上创建一个用户,减少不必要的沟通成本 如何在Linux系统中查看CPU信息使用lscpu命令行 linux服务器搭建ftp的6下安装vsftpd步骤及步骤 贵州工业职业技术学院求职意向期望工作地--诚聘英才 实验1Linux安装实验掌握虚拟机的使用 Linux系统tar命令的使用方法及使用命令教程 linux 开源nas系统 杰和科技NAS服务器媒体见面会在京召开 Android与Linux开发大不同 Linux系统软件安装包:自己动手,安装不用愁 车市新战局:汽车操作系统会复制智能手机的历史吗? Linux文件系统种类 如何卸载用源码包安装的软件?在线视频教程推荐 「职位」ASP.、PHP、Linux服务器集群开发 Torvalds:Linux内核开发的创新前景充满了热情 Linux文件系统的结构从终端窗口探索Linux目录树结构 卸载软件命令Linux.You linux软件开发如何入门?学习Linux步骤及学习方法介绍 14年Linux发行版的有趣历史观点
嵌入式Linux操作系统学习规划+LINUX路线,主攻江苏电信天翼校园客户端故障指引及解决办法(101)英特尔GMAGMA950显卡驱动程序/WIN8/8.1电信校园网宽带用USB数据线共享给电脑无线上网国防科大开源操作系统:它只是一个吉祥的象征10个常用Linux文本查看命令及其详细说明和使用示例Linux嵌入式系统内核裁剪与定制方法的介绍情况淘宝教育热卖C语言编程开发C++程序设计零基础入门课程从CPU、内存、硬盘、显卡等这些方面安装Linux系统的最低配置Linux通过chkconfig设置开机启动服务创建的几种常见方式(技术分析)Linux多线程的使用与操作系统的区别通常rar命令由一个主命令加若干选项(可选)构成RedHatLinux中自动运行程序中的应用linux 读写文件 关于Linux内核的神秘面纱,你知道几个?使用wget实用程序的有用命令行工具的使用怎么设置linux开机项自启动?方式是怎样的?嵌入式Linux应用层与驱动层要想学习关于Linux内核的交叉编译步骤和方法:步骤、方法STM32嵌入式linux开发流程及应用程序分析-STMlinux下有哪些文件在介绍lsof命令实用用法介绍?
:2管理大部分命令的组成 iOS设备如何安装deb文件管理插件?越狱的方法 Linux常见的安装为tar,zip.version.Brpm卸载 掌握Linux编译C语言的命令,轻松使用编译器 在单片机与嵌入式linux的应用与驱动操作(组图) 如何查看Linux系统中systemd可管理的所有服务 home/ftproot/scb添加权限,你的第一个要求是什么? Linux系统默认的根目录结构和文件参数实例target作为 如何在Linux上创建可执行文件? Ubuntu系统更改IP地址的简易教程,跟随以下步骤即可搞定! linux常用命令介绍--常用的命令 掌握Linux下载文件命令技巧,轻松高效获取所需资料 多台服务器时间保持一致怎么做才能做到呢?怎么做到? 变量置为昨天的日期,并将其转换为Unix时间戳 物理端口和逻辑端口、端口号等计算机概念的区别 虚拟网络编辑器网络配置教程,各个方法都不一样! unix系统 鸟哥的Linux私房菜-基础学习篇(第三版) Linux设置显示中文和设置字体设置中文一个都不能少 查看Linux内核Kernel的场景情况查看的几种方式 Unix系统下的安装在Unix平台下安装PHP的方法
标签聚合
linux系统 软件 虚拟机 命令 操作 linux服务器 应用 内核 文件目录 文件
书籍
课程
技术群
技术干货大合集↓
  • 2023年9月 / 81篇
  • 2023年8月 / 93篇
  • 2023年7月 / 94篇
  • 2023年6月 / 90篇
  • 2023年5月 / 93篇
  • 2023年4月 / 90篇
  • 2023年3月 / 129篇
  • 2023年2月 / 84篇
  • 2023年1月 / 161篇
  • 2022年12月 / 187篇
  • 2022年11月 / 76篇
友情链接:

Linux书籍 | Linux命令 | Linux系统 | RHCE红帽认证 | Linux软件 | Linux教程 | CentOS系统 | Linux内核 | Linux服务器 | Linux大神 | IT资源

COPYRIGHT © 2023 linuxgod.net ALL RIGHTS RESERVED.