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

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

2023年2月12日 372点热度

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大神网

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

最新 热点 随机
最新 热点 随机
VMware过期Linux系统CentOS7下载安装1.77下载地址 红旗linux操作系统v11.0-红旗操作系统操作系统吗? 5yw红软基地驱动完美支持windows、mac、linux系统 轻松安装ZeroMQ:Ubuntu系统必备的解决方案 怎么在Win7系统虚拟机上安装LinuxUbuntu的技巧?在这里 Linux必备!安装RAR解压器,轻松解压文件! 虚拟机linux系统下载 什么是linuxLinux(/托瓦兹)的Linux内核 文件永久删除还能找回来吗?关于Win和Mac系统的恢复方法 Ubuntu16.04怎样安装系统更新和应用更新16.04 网卡 centos 启动 Linux选择选择时各企业所参考的依据:以下内容和Centos Linux内核内存检测工具系列中的一篇,配置以及典型应用 虚拟机安装Ubuntu操作系统-Ubuntu空间20G镜像下载 0渗透操作0x02绕过disable_functions插件(组图) 【好玩的网络-第2.5期】分配IP有哪些骚操作?小白保姆级教程 Windows远程连接工具、Ubuntu系统的安装软件及系统 Linux一模一样远程连接编辑的操作图是什么? DRAM中的虚拟地址空间的缓存简化内存管理(组图) 2.5创建和配置虚拟机2.5.1创建虚拟机双击桌面的VMwarePlayer 掌握Linux基础命令-上海怡健医学系统 服务器上安装linux系统的具体操作过程-如何选择系统?
Linux文件路径查询方法,轻松获取文件位置Linux移植6410:从零开始的挑战!linux php安装 快速掌握Linux下PHP安装,轻松入门流行技术linux patch 文件 解决LinuxPatch文件10大疑难杂症,轻松应对!Ubuntu系统更改IP地址的简易教程,跟随以下步骤即可搞定!高效搭建Linux Android开发环境,轻松提升开发体验轻松掌握:如何查询Linux内核版本?Linux安装Matlab指南,快速掌握安装步骤Ubuntu 16安装网卡驱动教程,轻松解决网络连接问题Linux启动时,不使用图形界面可能更有效率!移植Linux,手机变身“大杀器”!详解8大关键操作Linux更高效,掌握启动终端快捷键!纯Python库实现上面介绍的HTML转换为PDF的软件Fedora 13服务器配置指南:9个实用技巧全解析9种方法轻松获取Linux版本,快速掌握系统信息!博客韦东山freeRTOS系列教程:入门文档教程+进阶视频教程轻松掌握linux ldd命令的技巧,成为高效开发者与管理员Linux VPS安全检测,保障服务器稳定运行!Linux下高效开发必备:配置Tomcat和JDK分析Linux中的I2C驱动程序框架核心结构(i2c-bus结构)
1.8中是增加了dnsmasq服务,它可以通过命令unbound直接启动服务 《深入linux设备驱动程序内核机制》(1)_社会万象_光明网(图) 教你在XShell软件中使用sz和rz命令下载和上传文件 armlinux与windows使用tftp进行文件传输的简单整理目录(一) Linux预置七种运行级别在/inittab目录下的内核文件 如何显示英语总是默认支持的是中文? 使用`uname`命令查看Linux内核版本的新安全漏洞系统 双核虚拟机中有中有两个线程函数执行(多CPU) Linux下的开机启动设置方法是什么?脚本或服务 如何找到Linux内核的版本号?或全部答案来修复 Linux软件安装目录及位置4种方法(服务器学习) 渗透测试最重要的阶段之一DNS枚举工具 完后,目录可以自动生成,如何生成可参考右边的帮助 一下,网络编程环境高级编程(第二版) Linux部署项目:构建高效稳定的运行环境 华为手机刷机软件V1.2.5官方版软件说明软件介绍 在文档中查找字符串用grep命令的使用:几个 Linux下中文乱码具体处理方法是什么?的人对电脑的操作 下的脚本文件就是运行级别是第5级随机启动的服务程序 如何实现局域网内的文件夹共享?全面详细详细地向
标签聚合
虚拟机 命令模式 命令 软件 linux系统 sudo linux脚本 电脑 linux服务器 文件目录
书籍
课程
技术群
技术干货大合集↓
  • 2023年3月 / 112篇
  • 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.