精华内容
下载资源
问答
  • C语言源文件到汇编语言的编译

    千次阅读 2016-11-04 23:08:17
    这是我们经常写最简单程序: #include ...在我们使用gcc指令来编译C语言源文件的时候,在命令行输入下面命令: [root@localhost kangkang]# gcc -o hello hello.c //#编译C代码生成目标文件为hello。

    这是我们经常写的最简单的程序:

    #include <stdio.h>
    int main()
    {
    printf("Hello,world!\n");
        return 0;
    }

    在我们使用gcc指令来编译C语言源文件的时候,在命令行输入下面命令:

    [root@localhost kangkang]# gcc -o hello hello.c   //#编译C代码生成目标文件为hello。

    默认情况下,gcc指令将编译连接过程一步完成,使用适当的选项可以将编译过程分步骤完成。使用“-E”选项仅完成编译预处理操作:

    [root@localhost kangkang]# gcc -E -o hello.i hello.c   //#仅执行编译预处理,指定预处理后生成的文件。

    接下来,使用“-S”选项生成汇编代码。在命令行中输入下面的命令:

    [root@localhost kangkang]# gcc -S -o hello.s hello.i    //#将C语言转换为汇编源代码文件“hello.s”  。

    最后,使用cat指令查看生成的“.s”文件:

    [root@localhost kangkang]# cat hello.s
            .file   "hello.c"
            .section        .rodata
    .LC0:
            .string "Hello,world!"
            .text
    .globl main
            .type   main, @function
    main:
            leal    4(%esp), %ecx
            andl    $-16, %esp
            pushl   -4(%ecx)
            pushl   %ebp
            movl    %esp, %ebp
            pushl   %ecx
            subl    $4, %esp
            movl    $.LC0, (%esp)
            call    puts
            movl    $0, %eax
            addl    $4, %esp
            popl    %ecx
            popl    %ebp
            leal    -4(%ecx), %esp
            ret
            .size   main, .-main
            .ident  "GCC: (GNU) 4.1.2 20070626 (Red Hat 4.1.2-14)"
            .section        .note.GNU-stack,"",@progbits

    使用as指令的“-o”选项可以将汇编代码文件编译为目标文件:

    [root@localhost kangkang]# as -o hello.o hello.s      //#将汇编文件编译为目标文件。

    展开全文
  • 文章目录一、编译输入输出二、编译过程三、编译第一阶段1)语法分析四、编译第二阶段1)语法分析2)语法分析器五、编译第三阶段1)语义分析2)语义分析器3)常见的语言错误(警告)六、编译器第四阶段1)生成中间...

    本专栏总结王利涛《C语言嵌入式Linux高级编程》第三期课程

    一、编译输入输出

    • (1) 输入:C程序源文件;
    • (2)输出:汇编文件,目标文件;
    • (3)编译过程主要做了什么?
      • 从高级语言到低级语言的转变
        • 程序语句:函数 ---->代码段;
        • 变量、常数----->数据段、BSS段、rodata段;
        • 各种辅助信息----->符号表、重定位表。

    二、编译过程

    • 基本过程:
      词法分析;
      语法分析;
      词义分析;
      中间代码生成;
      汇编代码生成;
      目标代码生成。

    三、编译第一阶段

    1)语法分析

    • 从左到右,一个字符一个字符读入源程序;
    • 对源程序的字符流进行扫描,分解成一系列记号:token;
    • 常见记号:
      关键字、标识符(函数名、变量名、标号等)
      字面量(数字、字符串等)
      分界符(分号、逗号等)
    • 将标识符存到符号表,将数字、字符串存放到字符串表。
    • 词法扫描器
      ①该阶段主要由词法扫描器完成,比如lex词法扫描器;
      ②采用有限状态机去解析并识别这些token、分界符、结束符;
      ③词法错误:遇到中文字符、圆角/半角字符会出错。
    • 举例:
      语句:sum = a+b/c;
      包含8个记号:“sun”、“=”、“a”、“+”、“b”、“/”、“c”、“;”

    四、编译第二阶段

    1)语法分析

    • 前一阶段产生的token序列进行语法分析,看是否构成一个语法上正确的程序,分解成语法短语(程序、语句、表达式等);
    • 语法短语用语法树表示,是一种树形结构,不再是线性序列;

    2)语法分析器

    • 专门的语法分析工具:yacc,对输入序列进行分析,构建出语法树;
    • 对于不同的编程语言,编译器开发者只需改变语法规则,而无需为每个编译器写一个语法分析器;
    • 语法错误:syntax error
      在这里插入图片描述

    五、编译第三阶段

    1)语义分析

    • 检查语法分析输出的语句、程序、表达式有没有错误;
    • 仅仅完成了语法层分析,对程序、语句的真正意义并不了解;
    • 静态语义:在编译期间能确定的语义
      函数实参形参类型匹配及转换;
      不允许使用一个未声明的变量。
    • 动态语义:在运行期间才能确定的语义
      比如:除数为0,

    2)语义分析器

    • 经过语义分析后,整个语法树的表达式都被标示了类型;
    • 如果源代码语义上没有问题,就会接下来进入下一个阶段;

    3)常见的语言错误(警告)

    • 使用一个未声明的变量或函数;
    • 函数的形参实参、返回类型不匹配、不兼容(默认类型转换后);
    • continue 语句不能出现循环语句之外;
    • break 不能出现在循环或switch语句之外。

    六、编译器第四阶段

    1)生成中间代码

    • 将语法树转换成中间代码;

    2)现代编译器构造

    • 前端:词法分析、语法分析、语义分析;
    • 优化端:对中间代码进行优化;
    • 后端:指令选择,寄存器分配。

    3)中间代码

    • 将源代码变成一种内部表示形式,这种形式称为中间代码;
    • 中间代码是一种记号系统,常见的有:三地址码。
    • 语法树是二维树结构,而中间代码可以看作一堆线性序列;
    • 特点:
      非常间接目标代码,类似于伪代码;
      容易生成,容易将其翻译成目标代码。

    4)为什么要使用中间代码?

    在这里插入图片描述

    5)三地址码

    • $arn-linux-gnuebigcc -fdump-tree-gimple main.c
    int main()
    {
    	int sum = 0;
    	int a = 2;
    	int b = 1;
    	int c = 1;
    	sum = a+b/c;
    	return 0;
    }
    

    三地址码↓↓

    main()
    {
    	int D.4226;  //定义了一些临时变量,最终被翻译成寄存器
    	int D.4227;
    	{
    		int sum;
    		int a;
    		int c;
    		sum = 0;
    		a = 2;
    		b = 1;
    		c = 1;
    		D.4226 = b/c;
    		sum = D.4226+a;
    		D.4227 = 0;
    		return D.4427;
    	}
    }
    

    七、编译第五阶段

    1)生成汇编

    • 指令选择: 将中间代码翻译成汇编文件;

    2)过程

    • 中间代码——》控制流、数据流分析、寄存器分配——》汇编语言;
    • 汇编语言——》汇编器——》目标文件。
    展开全文
  • 了Android 3.0,使用C代码就更方便了,我们通过工程向导设置使用C语言之后,向导会自动建立一个完整利用C++语言JNI工程,我们只要把默认那个恶心cpp源文件修改为C源文件即可。下面我将详细列出直接通过...

    从Android Studio 2.2起,我们可以直接通过CMake在Android Studio中写C源代码以及汇编代码,而不需要通过NDK编译工具链生成好.so文件后再导入到工程中。

    而到了Android 3.0,使用C代码就更方便了,我们通过工程向导设置使用C语言之后,向导会自动建立一个完整的利用C++语言JNI的工程,我们只要把默认的那个恶心的cpp源文件修改为C源文件即可。下面我将详细列出直接通过Android Studio 3.0来编写C代码和汇编代码的步骤。对于其中的细节,如果各位有条件的话可以参考Android开发者官网中关于NDK的信息:

    这条是关于CMake的:https://developer.android.com/ndk/guides/cmake.html

    这条是关于在项目中使用C++代码的:https://developer.android.com/studio/projects/add-native-code.html


    1、下载Android Studio 3.0,然后第一次打开Android Studio之后会弹出一个欢迎界面。我们点击右下角的Configure按钮,如下图所示。



    2、然后会弹出一个列表框,我们选择第一个:SDK Manager,然后会弹出如下图所示的对话框。我们在中间栏点击“SDK Tools”,这里需要至少增加三个选项——“CMake”,“LLDB”以及“NDK”。



    3、选完了之后,我们开始安装。安装完之后,我们开始新建一个全新的工程。我们在配置这个工程的时候可以根据自己的喜好进行设置,当然大部分用默认的配置即可,不过我们这里要增加对C语言支持的选项,如下图所示。



    4、这里勾选之后,后面的配置可以不用管。点击Finish之后需要等待一些时间让IDE做项目配置以及初始编译。最后我们进入到了主工程中。


    到了主工程中,我们先别着急去写C代码,因为此时还没有C源文件,我们可以先配置build.gradle(Module:app)配置文件,这里列出android配置部分:

    android {
        compileSdkVersion 26
        defaultConfig {
            applicationId "com.greengames.zennychen.ctest"
            minSdkVersion 23
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            externalNativeBuild {
                cmake {
                    // 使用NEON技术
                    arguments "-DANDROID_ARM_NEON=TRUE"
    
                    // C语言使用GNU11标准
                    cFlags "-std=gnu11"
                }
            }
            ndk {
                // Specifies the ABI configurations of your native
                // libraries Gradle should build and package with your APK.
                abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
    }

    这里各位请注意内部的cmake部分,这里使用了构建参数以及全局编译选项。然后再注意一下对ndk的配置,这里加入了在本项目工程中所支持的ABI架构。ABI架构可以根据自己的需求进行配置,不过笔者所列出的这几个已经能涵盖当前活跃的绝大部分的安卓设备了。


    接下去,我们可以把IDE自动生成的native-lib.cpp文件名修改为native-lib.c,然后编辑成以下C代码:

    //
    // Created by Zenny Chen on 2017/10/27.
    //
    
    #include <jni.h>
    #include <stdio.h>
    #include <string.h>
    
    #ifndef __x86_64__
    
    /**
     * 测试内联汇编,分别根据AArch32架构以及AArch64架构来实现一个简单的减法计算
     * @param a 被减数
     * @param b 减数
     * @return 减法得到的差值
     */
    static int __attribute__((naked, pure)) MyASMTest(int a, int b)
    {
    #ifdef __arm__
    
        asm(".thumb");
        asm(".syntax unified");
    
        asm("sub r0, r0, r1");
        asm("add r0, r0, #1");  // 为了区分当前用的是AArch32还是AArch64,这里对于AArch32情况下再加1
        asm("bx lr");
    
    #else
    
        asm("sub w0, w0, w1");
        asm("ret");
    
    #endif
    }
    
    #else
    
    extern int MyASMTest(int a, int b);
    
    #endif
    
    JNICALL jstring Java_com_greengames_zennychen_ctest_MainActivity_stringFromJNI
            (JNIEnv *env, jobject this)
    {
        char strBuf[128];
    
        sprintf(strBuf, "Hello from C! ASM test result: %d", MyASMTest(6, 4));
    
        return (*env)->NewStringUTF(env, strBuf);
    }
    

    上述C代码对AArch32与AArch64架构下的内联汇编以及对x86_64架构下待会儿要使用的独立的YASM汇编器编译的汇编代码进行了引用。下面我们可以在默认的cpp文件夹下再新增一个名为test.asm的汇编文件,输入以下x86_64的汇编代码:

    ; 这是一个汇编文件
    ; YASM的注释风格使用分号形式
    
    global MyASMTest
    
    section .text
    
    MyASMTest:
    
        sub     edi, esi
        mov     eax, edi
        ret
    

    最后,我们对CMakeLists.txt进行编辑,这里面需要引入YASM汇编器。

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.6.0)
    
    enable_language(ASM_NASM)
    
    if(${ANDROID_ABI} STREQUAL "x86_64")
        set(asm_SRCS src/main/cpp/test.asm)
    endif()
    
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    add_library( # Sets the name of the library.
                 native-lib
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 src/main/cpp/native-lib.c ${asm_SRCS})
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    find_library( # Sets the name of the path variable.
                  log-lib
    
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  log )
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
                           native-lib
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )

    我们这里使用了条件判断,只有在当前所编译的架构为x86_64的情况下才把test.asm给加入到所编译的库中。


    上述文件都编辑好之后,我们就可以开测了。如果各位没有x86的安卓设备,那么我们可以新建一个基于x86-64架构的模拟器,x86-64架构的模拟器运行速度还是挺快的,而对于ARM架构的处理器,我们最好用真机来测。


    最后,笔者提供一下各位可用于参考的Google官方给的使用Android Studio来写JNI的例子:https://github.com/googlesamples/android-ndk


    这篇Wiki文章则比较详细地介绍了NASM的汇编基本用法:https://en.wikipedia.org/wiki/Netwide_Assembler


    由于YASM衍生自NASM,因此在语法和用法上都差不多,并且YASM使用了更自由的BSD License,因此各位可以毫无顾虑地使用~



    展开全文
  • 链接LinkingC语言编译过程gcc的编译流程分为四个步骤,分别为:・ 预编译(Pre-Processing) ・ 编译(Compiling) ・ 汇编(Assembling) ・ 链接(Linking)-E 预编译预编译的主要作用如下:将源文件中以”...

    C语言编译过程

    gcc的编译流程分为四个步骤,分别为:

    ・ 预编译(Pre-Processing)
    ・ 编译(Compiling)
    ・ 汇编(Assembling)
    ・ 链接(Linking)

    -E 预编译

    预编译的主要作用如下:

    将源文件中以”include”格式包含的文件复制到编译的源文件中,同时将代码中没有用的注释部分删除
    hello.c

    //hello.c
    #include <stdio.h>
    
    int main()
    {
        printf("hello world\n");
        return 0;
    }
    

    预编译hello.c,输出为hello.e

    gcc -E -o hello.e hello.c //大写的E就是预编译

    这里写图片描述

    -S 编译

    -S就是将C语言转化为汇编语言

    gcc -S -o hello.s hello.c

    这里写图片描述

    -C 汇编

    转为机器码

    gcc -c -o hello.o hello.s
    

    这里写图片描述

    链接(Linking)

    刚刚一直到这个步骤,其实代码都不能执行。

    最后一步链接,需要在二进制文件 hello.o 的基础上,生成可执行文件 hello.out 

    gcc -o hello.out hello.o
    

    参考链接:
    http://mooc.guokr.com/note/13202/
    http://blog.csdn.net/gengshenghong/article/details/7096709

    展开全文
  • C语言编译过程详解

    2020-11-11 09:48:43
    C语言是一种编译型语言,需要把源文件进行编译之后才能运行,它的编译过程如下: 预处理:展开头文件、宏替换,去掉注释,条件编译 编译:检查语法,生成汇编 汇编:把生成的汇编文件汇编成机器码 链接: 链接...
  • 分别是 第一行,可执行文件 (-o 是指可目标文件) c语言源文件 经过预处理c源文件代码 编译目标文件 汇编语言源代码文件》》》c语言源文件2,经历四个步骤 1)c源文件到预处理c预处理源文件 ...
  • 众所周知,C语言是高级语言,它是由机器语言,汇编语言逐步演化而来,并非计算机可以直接识别。所以我们要将C语言转化为计算机可以识别语言,就要进行编译和链接。 2.编译链接过程 2.1 编译过程 预处理 ...
  • 1:预处理阶段有预处理器进行,会将每一个.cpp(源文件c语言程序和c++语言程序是一样)预处理器会将所有源文件与预处 理指令进行处理,所谓预处理执行就是 #开头语句 如#define #include #if 1 #endif ...
  • gcc的编译流程详解

    2016-10-18 10:00:58
    C语言是编译型的语言,必须经过编译器的编译才能在内存中加载被处理器执行,从C语言源文件到最终的处理器能够执行机器码,是我们通常所说的”编译“,这是个模糊的概念,实际上需要预处理、编译、汇编、链接四个...
  • 这张图展示了大体上步骤。 ...1,语法分析(判断是否存在语言的语法错误而造成无法编译) 2,词法分析 3,语义分析(分析每句代码的意思) 4,符号汇总(会将整个程序中的全局符号进行汇总) 汇.
  • c语言复习笔记一

    2017-08-23 16:10:43
    1解释语言编译语言语言本身没有这些分别,只是我们常用的到执行这种类型 Python是解释型语言,不需要编译 解释就是借助一个程序,那个程序能够理解我程序,并按照要求执行 C语言编译语言 源文件.c ->...
  • 你必须知道495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    可我找不任何方法来声明这样函数——感觉我需要一个返回指针函数,返回指针指向又是返回指针函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致局部数组,或者由其他参数...
  • C源文件到可执行文件共经历了4个过程。在使用GCC编译程序时,编译过程可以被细分为四个阶段,包括预处理、编译汇编、链接。 1、源代码文件 存放程序代码文件,即我们编辑代码文件,称为源代码文件。 ...
  • 我们知道gcc是一个强大的编译器,很多Linux下的GNU工具都是用C语言写的,并且用gcc编译的,那么gcc的编译...2. 从预加载的文件经过编译就会变成汇编语言的文件,这一步可以通过-S这个参数来生成这个中间文件 。 3. ...
  • 《你必须知道495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    《你必须知道495个C语言问题》以问答形式组织内容,讨论了学习或使用C语言的过程中经常遇到一些问题。书中列出了C用户经常问400多个经典问题,涵盖了初始化、数组、指针、字符串、内存分配、库函数、C预...
  • C语言的源文件编译汇编语言源文件 汇编 将汇编语言源文件传化成机器语言文件,即目标文件 链接 将目标文件链接成可执行文件   前三个过程相对而言,不是很复杂。重点放在链接过程如何将多个目标文件链接成可...
  • 可我找不任何方法来声明这样函数——感觉我需要一个返回指针函数,返回指针指向又是返回指针函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致局部数组,或者由...
  • linux gcc编译C程序

    2014-10-25 20:24:00
    一个c语言程序从源文件到生成可执行文件,编译器需要共经历4个步骤: 1)预处理:把c文件中预处理命令扫描处理完毕,即对源代码文件中文件包含(#include)、预编译语句(如宏定义#define等)进行分析,此时生成文件...
  • 你必须知道495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    难道在C语言中一个结构不能包含指向自己指针吗? . . . . 3 1.7 怎样建立和理解非常复杂声明?例如定义一个包含N 个指向返 回指向字符指针函数指针数组? . . . . . . . . . . . . . . 3 1.8 函数只定义...
  • 6•C语言允许直接访问物理地址,能进行位(bit)操作,能实现汇编语言的大部分功能,可以直接对硬件进行操作。因此有人把它称为中级语言。 7•生成目标代码质量高,程序执行效率高。 8•与汇编语言相比,用C语言写的...
  • 一个c语言程序从源文件到生成可执行文件,编译器需要共经历4个步骤: 1) 预处理:把c文件中预处理命令扫描处理完毕,即对源代码文件中文件包含(#include)、预编译语句(如宏定义#define等)进行分析,此时生成...
  • o 6.13 考虑有关空指针所有这些困惑, 难道把要求它们内部表达都必须为 0 不是更简单吗? o 6.14 说真, 真有机器用非零空指针吗, 或者不同类型用不同表达? o 6.15 运行时 ``空指针赋值" 错误是什么意思...
  • 建议您优先选择TXT,或下载源文件到本机查看。 51 单片机设计跑马灯程序用(c 语言)编写 P1 口接 8 个发光二极管共阳,烧入下面程序 #include unsigned char i; unsigned char temp; unsigned char a,b; void ...
  • GCC 生成符号表调试信息剖析

    千次阅读 2014-07-19 18:36:14
    GCC把C语言源文件('.c')编译汇编语言文件('.s'),汇编器把汇编语言文件翻译成目标文件('.o'),最后由链接器链接所有目标文件和有关库生成可执行文件('a.out')。 如打开'-g'选项,GCC编译'...

空空如也

空空如也

1 2 3
收藏数 60
精华内容 24
关键字:

c语言源文件到汇编语言的编译

c语言 订阅