理解计算机系统_程序的机器级表示(一):程序编码和数据

前言

        以<深入理解计算机系统>(以下称“本书”)内容为基础,对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定

引入

        本书第三章:程序的机器级表示内容的理解,这一章内容以汇编语言为主.汇编语言偏底层,用于系统级别的程序编写.如果不是做系统的,可以不用深入学习.理解汇编语言的关键是理解gcc指令,数据,寄存器,地址等概念.这些概念在C语言中也是很重要的,而且从汇编语言的角度会发现更多细节.

        这章可以作为学习C语言的辅助,明白C语言的运行机制.其中重点关注能优化代码的部分.

        本帖内容为3.1~3.3节,3.1节属于CPU的发展历程,了解即可.

3.2程序编码

        一.gcc命令和代码转换

        1>gcc的概念

                本书P113

linux> gcc -Og -o p p1.c p2.c

                gcc:GCC C编译器 

                -Og:编译优化等级.g表示较低优化等级,符合原始C代码整体结构方便学习.

                        实际使用-O1或-O2提高优化等级

                -o:运行链接器,生成可执行文件

                p:生成的可执行文件名.

                整个语句的意思是:把文件p1.c和p2.c转换成可执行文件p.

                实际上gcc命令调用了一整套程序,将源代码转化成可执行代码(黑体字是本书原话)

        2>从C文件到机器代码转换过程

                如下图所示:

                 左起是C语言代码,预处理成为后缀为i的文件,经编译器编译后成为.s文件.经汇编器成为.o文件(目标代码),他是机器代码的一种形式,经链接器链接库函数后,成为可执行文件,他是机器代码的第二种形式.目标代码和可执行文件这两种机器代码是十六进制数,无法直接阅读.学习内容是查看.s文件,即汇编代码.

                转换过程中出现了iso(国际标准化组织的缩写),比较好记.

        3>机器级编程的抽象

                本书P113页3.2.1下面第一段讲了两个非常重要的概念:指令集架构虚拟地址.

                虚拟地址:提供了对物理地址的抽象.程序员面对的是一个巨大的连续的内存空间,是虚拟地址,而虚拟地址对应的实际硬件地址不是连续的,需要作转换.

                指令集架构:代码的运行,在机器(芯片)层面上,体现为(许多)晶体管的开(1)和关(0)的.(注:1和0也可能反过来,由晶体管性质(pnp)或者(npn)决定).指令提供了描述机器运动的抽象.程序员通过指令来控制数据的变化,并以此表达逻辑.指令集架构是一套指令的规范. 

                不同芯片厂家使用的指令集架构可能不一样.所以指令集也可以看作是对芯片的抽象.笔者认为不同的指令集架构差别并不大,就算差别大,也不会影响程序员使用,他们设计的原则都是方便程序员编写代码.

        4>gcc生成各种代码的指令

        1.生成汇编代码:-S

        示例:本书P114        

linux> gcc -Og -S mstore.c

        结果:生成mstore.s文件---汇编代码,程序员可以读懂的

         2.生成目标代码:-c

        示例:本书P115        

linux> gcc -Og -c mstore.c

        结果:生成mstore.o文件---目标代码  

        3.生成可执行文件:-o 

        示例:本书P113

linux> gcc -Og -o p p1.c p2.c

        结果:生成p---可执行文件.

        生成实际可执行代码需要对一组目标代码文件运行链接器(黑体字是原话),其中某个文件(.c)必须有main函数,原因是提供程序入口.

        从上面可以看出,gcc指令不是"线性"工作的,可以根据需要生成gcc支持格式的代码 

        5>反汇编器:objdump -d

        机器代码(包括目标代码和可执行代码)是一连串的十六进制数,不方便阅读,因此需要将其转换为较为符合阅读习惯的汇编代码 .反汇编器可以用在目标代码和可执行代码上

        示例:本书P115---反汇编目标代码

linux> objdump -d mstore.o

        反汇编可执行文件 

linux> objdump -d p        //和上面生成可执行文件的代码对应
         二.汇编代码格式

        本书汇编代码格式采用ATT(贝尔实验室AT&T),此外还有Intel格式,了解即可.

        三.为什么使用汇编代码和汇编代码的写法

        本书P118方框内容"把C程序和汇编代码结合起来"说了使用汇编代码的原因:访问C程序访问不到的机器的低层特性.举了个例子:条件码标志的访问.

        可以这样理解:C程序封装了汇编代码,但某些在汇编代码层面的数据,没有给C程序提供接口,因此需要写汇编代码来作数据访问.

        汇编代码的写法有两种:第一种方法是汇编代码编写整个函数,在链接阶段把他们和C函数组合起来.第二种方法是利用GCC的支持,直接在C程序中嵌入汇编代码.很显然第二种方法是更容易被接受的.本书P118倒数第二段:用asm伪指令可以在C程序种包含简短的汇编代码(黑体字是原话),具体写法笔者也不知道,所以不展开,用到的时候再查资料.

         本书P119第一段做了说明:C程序中包含的汇编代码与某类机器相关,所以只应该在想要的特性只能以此种方式才能访问到时才使用它.(黑体字是原话)

        这段话笔者解读为两层含义:

        一是使用汇编代码的情况不多.站在C的角度,编写代码的原则必定是和机器无关.(和Java的跨平台一样,写代码不用去考虑在什么平台运行,C写出来的程序面对的始终是gcc翻译),以此推导如果要用到汇编代码的时候,那就要访问机器的底层.而此时使用的指令集架构不同,数据的表示方法或许不同.以上面的条件码标志访问为例,可以需要区分X86架构或者RISC架构的表示

        二是在上面那段话描述的情况下,代码想要通用(一次编写多处使用)需要分支结构

//伪代码
if(expression_A){        //expression_A:架构A在C语言中的表示
    asm:
        汇编代码;
}
else if(expression_B){   //expression_B:架构B在C语言中的表示
    asm:
        汇编代码;
}
    

        说明:因为目前对架构的了解不多,上述属于笔者个人解读,未必如此.

3.3数据格式 

         这一节的内容就在这张图里,基本上也是耳熟能详的,比较好记.

         数据后缀说明:

                b(字节)        w(字/2字节)        l(双字/4字节)       q(四字/8字节)

         指针的长度等于计算机字长,64位机器的字长为8字节.所有指针(不光是图中的char*)长度都是8字节,这点也可以在程序中用sizeof(int*)---(或者其他类型指针,这里用了int*)来查看.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jllws1

你的鼓励是我创作的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值