深度探索C语言(一) —— 引子和基础知识技能 (原创:大鱼蓝鲸)

来源:互联网 发布:ubuntu中文语言包 编辑:程序博客网 时间:2024/04/29 20:28

大鱼蓝鲸原创,欢迎转载!

http://blog.csdn.net/i_am_back

一 引子

C语言对于大家可能都很熟悉,不过部分深层次的理解和认识可能还存在些不足,如:if else 和 switch 区别,全局(自动)变量和全局静态变量的区别和差异。

 

现在在这里,借《深度探索C语言》之名,和大家一起深入C语言进行探索

 

二 深入探索基础知识技能

这里介绍一些本文后面使用的知识和技能,大家如果已经掌握,或兴趣不大,可以跳过 o(∩_∩)o...

 

2.1 编译与链接

    编译分4个阶段:(1)预处理 (2)编译 (3)汇编处理 (4)链接

   (1)预编译:

           预编译根据以字母#开始的指令修改原始编译的.c文件,如test.c文件中有 #include <stdio.h> ,则预处理器会读取系统的文件 stdio.h 并直接插入到编译文件中,经过预处理后的文件,通常为 .i文件。

   (2)编译:

           编译就是将C指令经过词法分析和语法分析处理,将C语言编译为汇编指令的过程。这个过程一般都是用yylex词法分析器进行。

           通常是编译器将文本文件.i 翻译成汇编指令文本.s的过程。

           这个阶段对于声明的外部变量,采用占用符号来代替,在最后的链接才真正使用变量的地址替代。

   (3)汇编处理:

           汇编处理是将汇编指令和机器指令一一对应翻译的过程,这个阶段会对代码中的调用函数进行打包,打包成可重定位代码目标格式。

           注: 可重定位代码是可以在足够大的任何内存区域中运行的目标指令。在可重定位目标指令文件中,每个调用指令都不是固定的,地址是相对地址。

   (4)链接阶段:

           先将链接的各个目标文件中使用到的外部变量通过并入处理在程序中使用真实的定义地址替代原先编译过程的占位符;

           再将各个目标文件中调用的外部函数并入程序文件中,同时进行实际的函数调用地址替换。

           最终得到的程序文件就是一个可执行的目标文件,简称可执行程序。

 

2.2 预备编译知识

    后续我们很多部分需要通过C编译器输出的汇编代码来分析C语言的内部实现,故这里也介绍一下后续我们常用的一些汇编指令,采用Intel风格讲解,至于linux下的AT&T汇编风格,末尾会给一个差异说明。

    PUSH SRC

    指令动作:

          esp = esp - 4    ;栈寄存器(地址)压一个sizeof(int)

          [esp] = SRC      ;栈地址赋值为SRC内容

 

    POP DEST

    指令动作:

         DEST = [esp]     ;目标变量赋值为栈地址指向的内容

         esp = esp + 4    ;栈寄存器(地址)弹出一个sizeof(int)

 

   MOVE DEST, SRC

   指令动作:

         DEST = SRC

   例子:

        move eax, ebx

        move [ebx], 1234

   注:

        MOVE 指令需要遵循的规则,参数必须遵循下面规则

        (1)寄存器与寄存器之间

        (2)寄存器与存储器(内存)之间

        (3)寄存器与立即数(常量)之间

 

   LEAVE

   指令动作:

        MOVE esp, ebp

        POP    ebp        

 

   RET

   指令动作:

        POP eip

        (然后CPU从[eip]开始执行)

 

  CALL SRC

  指令动作:

       PUSH eip

       eip = SRC (然后CPU从[eip]开始执行)

 

   ADD DEST, SRC

   指令动作:

        DEST = DEST + SRC

 

   SUB DEST, SRC

   指令动作:

        DEST = DEST - SRC

 

LINUX操作汇编风格与WINDOWS上存在些许差异,主要可以归类如下4点:

(1) AT&T汇编指令带有后缀,用于表示操作的位数。

         B表示8位, W表示16位, L表示32位

         例如: movb %eax, %ebx

                   movw %eax, %ebx

                   movl %eax, %ebx

(2) AT&T汇编源操作数和目标操作时与INTEL汇编指令操作数位置相反

         Intel:  move dest, src

         AT&T: movb src, dest

(3) AT&T寄存器前面加%, 常量(地址)前面加$

        例如:

        AT&T:           movl $1234, %ebx 

        等同 Intel:    move ebx, 1234

(4)间接地址使用圆括号,偏移地址写在括号外面

         Intel:  move eax, [ebx + 4]

         AT&T: movl   4(%ebx), %eax       

            

  2.3 编译与反编译 -- Linux

  (1)编译汇编

        使用gcc命令可以将.c文件编译出对.c文件的汇编指令,结果存放在对于的.s文件中。

        例如: gcc -S test.c    

  (2)反编译:

        使用objdump命令可以将目标.o文件反编译出汇编指令。

        例如: objdump -d test.o

 

本篇内容没什么含量,有些枯燥 o(∩_∩)o...

后面一片,我们一起探讨if else 和 switch写法差异,包括汇编指令和性能分析,欢迎大家参与,谢谢!

 

大鱼蓝鲸原创,欢迎转载!

http://blog.csdn.net/i_am_back

 

 

原创粉丝点击