`
gashero
  • 浏览: 966860 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Tiny C Compiler参考手册

    博客分类:
  • C
阅读更多

 

Tiny C Compiler参考手册

译者: 原文:
gashero
http://bellard.org/tcc/tcc-doc.html

1   简介

TinyCC (简称TCC)是一个小且很快的C编译器。不像其他C编译器,他可以自依赖:你不需要扩展汇编器或连接器,因为TCC已经为你准备好了。

TCC编译速度奇快,以至于Makefile都不是那么必要了。

TCC不仅仅支持ANSI C,还支持ISO C99标准和很多GNU C扩展,包括内联汇编。

TCC还可以用于C脚本,例如一段C代码可以像Perl或Python脚本那样运行。编译速度很快,有如可执行文件一样。

TCC还会自动生成所有C指针操作的内存边界检查。TCC做这些是无需补丁库的。

使用libtcc,你可以用TCC作为动态代码生成的后端。

TCC主要支持Linux和Windows的i386目标。还有个alpha状态的ARM(arm-tcc)和TMS320C67xx(c67-tcc)目标。更多信息关注 http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html

关于在Windows上的使用,查看 tcc-win32.txt

2   命令行选项

本手册基于Tiny C Compiler 0.9.25。

2.1   快速入门

使用:

tcc [options] [infile1 infile2 ...] [`-run' infile args ...]

TCC选项非常像gcc的选项,主要的不同在于TCC可以直接执行结果程序,并赋予它运行时的参数。

如下是一些逻辑的理解:

``tcc -run a.c``
编译 a.c 然后直接执行。

tcc -run a.c arg1

编译 a.c ,然后执行,并将arg1参数传递到 a.c main() 函数。

tcc a.c -run b.c arg1

编译 a.c b.c ,然后将他们连接到一起并执行。参数arg1作为结果程序 main() 的第一个参数。

tcc -o myprog a.c b.c

编译 a.c b.c ,然后连接成可执行文件 myprog

tcc -o myprog a.o b.o

连接两个目标文件,生成输出文件 myprog

tcc -c a.c

编译 a.c ,生成目标文件 a.o

tcc -c asmfile.S

asmfile.S 使用C预处理器和汇编器,并生成目标文件 asmfile.o

tcc -c asmfile.s

直接汇编,不做预处理,生成 asmfile.o

tcc -r -o ab.o a.c b.c

编译 a.c b.c ,并且把他们连接到一起,生成一个目标文件 ab.o

脚本:

TCC可以从脚本调用,有如shell脚本一样。你只需要将 #! /usr/local/bin/tcc -run 加到你的C源码开头即可:

#! /usr/local/bin/tcc -run
#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

TCC可以使用"-"选项,从标准输入读入C源码来替换输入文件,例如:

echo 'main(){puts("hello");}' | tcc -run -

2.2   选项摘要

常用选项:

-v

显示TCC版本,增加显示信息。

-c

生成目标文件。(必须给定"-o"选项)

-o outfile

输出目标文件、可执行文件、或者dll文件到outfile。

-Bdir

设置tcc内部库的搜索路径,缺省是 PREFIX/lib/tcc

-bench

输出编译统计。

-run source [args ...]

编译源文件并使用参数args来运行。为了给出更多选项到脚本,一些TCC选项可以在 -run 之后给出,空格分割,例如:

tcc "-run -L/usr/X11R6/lib -lX11" ex4.c

在脚本中使用如下头:

#! /usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>

int main(int argc, char** argv) {
    ...
}

预处理选项:

-Idir

指定附加的头文件路径。按照给出的顺序搜索。系统搜索路径总是排在最后。缺省系统头文件路径是: /usr/local/include /usr/include PREFIX/lib/tcc/include (PREFIX通常是 /usr 或者 /usr/local )。

-Dsym[=val]

定义预处理器符号 "sym" 到 val。如果val没有给出,则缺省值为1。这里也可以定义函数风格的宏,例如 -DF(a)=a+1

-Usym

删除预处理器定义的符号 sym

编译标识:

注意如下每个警告选项都可以换用 -fno- 前缀。

-funsigned-char

让char类型变成无符号的。

-fsigned-char

让char类型有符号。

-fno-common

不为未初始化数据生成普通符号。

-fleading-underscore

为每个C符号添加下划线前缀。

警告选项:

-w

禁用所有警告。

如下每个警告选项都可以换用 -Wno- 前缀。

-Wimplicit-function-declaration

警告所有隐含(implicit)函数。

-Wunsupported

警告所有不支持的GCC的功能。

-Wwrite-string

让字符串常量类型使用 const char * 而不是 char *

-Werror

发生警告时中断编译。

-Wall

激活所有警告,除了 -Werror -Wunsupported -Wwrite-strings

链接选项:

-Ldir

指定附加的静态库路径,用于 "-l" 链接选项。缺省库路径是 /usr/local/lib /usr/lib /lib

-lxxx

链接指定的动态库 libxxx.so 或静态库 libxxx.a 。搜索库路径是由 -L 选项提供的。

-shared

生成动态库,而不是可执行文件(必须使用"-o"选项)。(不确定)

-static

生成静态链接可执行文件(缺省是动态链接)(必须用"-o"选项)。(不确定)

-rdynamic

导出动态符号到动态连接器。这对于使用 dlopen() 打开的库访问可执行符号表很有用。

-r

生成对象文件包含所有的输入文件(必须用"-o"选项)。

-Wl,-Ttext,address

设置 .text 段的位置到address。

-Wl,--oformat,fmt

使用fmt作为输出格式。支持的格式包括:

  1. elf32-i386 :ELF格式(缺省)
  2. binary :二进制镜像(只用于可执行输出)
  3. coff :COFF格式(仅用于可执行输出到TMS320C67xx目标)

调试选项:

-g

生成运行时调试信息,以便得到运行时错误信息。给出无效指针,而不仅仅是段错误。

-b

生成检查内存分配和数组/指针边界检查的附加代码。自动包含 "-g" 选项。注意生成代码会又大又慢。

-bt N

显示N个调用者的回溯。与"-g"和"-b"使用时有用。

注意GCC选项"-Ox"、"-fx"、"-mx"会被忽略。

3   C语言支持

3.1   ANSI C

TCC实现了ANSI C的所有标准,包括结构体中的位字段和浮点数(long double、double,和float的完整支持)。

3.2   ISOC99扩展

TCC实现了新的C标准ISO C 99的很多特性。当前暂时不支持的包括:复数(complex)、虚数(imaginary)和变长数组。

当前实现的ISO C 99特性:

  • 64 bit的 long long 类型。

  • _Bool 布尔类型

  • __func__ 是一个字符串变量,包含了当前函数名字。

  • __VA_ARGS__ 可以用于函数样式的宏,如下定义后的 dprintf 就可以使用不定参数了:

    #define dprintf(level,__VA_ARGS__) printf(__VA_ARGS__)
    
  • 声明可以出现在代码块的任何地方,有如C++一样。

  • 数组和结构体/联合体元素,可以用任何方式初始化:

    struct {int x,y;} st[10]={[0].x=1, [0].y=2};
    int tab[10]={1,2,[5]=5,[9]=9};
    
  • 支持复合初始化。如下初始化了一个指向已经初始化过的数组的指针,对于结构体和字符串也可以:

    int *p=(int []){1,2,3};
    
  • 支持十六进制浮点数构造,如下两句一样:

    double d=0x1234p10;
    double d=4771840.0;
    
  • inline (内联)关键字会被忽略。

  • restrict (约束)关键字会被忽略。

3.3   GNU C 扩展

TCC实现了一部分GNU C扩展:

  • 数组赋值可以不用"=":

    int a[10]={[0] 1, [5] 2, 3, 4};
    
  • 结构体字段赋值可以不用标签:

    struct {int x, y;} st={x:1,y:1};
    //替代
    struct {int x, y;} st={.x=1, .y=1};
    
  • "\e" 是ASCII字符27。

  • case 范围:

    switch(a) {
    case 1...9:
        printf("range 1 to 9\n");
        break;
    default:
        printf("unexcepted\n");
        break;
    }
    

@waiting ...

3.4   TinyCC扩展

  • __TINYC__ 是一个预定义宏,值为1,用于指示使用了TCC。
  • 允许首行的 "#!" 指定脚本运行。
  • 支持二进制数字,例如 0b101 代表 5。
  • __BOUNDS_CHECKINT_ON 定义用于是否激活边界检查。

4   TinyCC汇编

自从版本0.9.16,TinyCC开始集成自己的汇编器了。TinyCC的汇编器支持gas-like语法(GNU汇编器)。你可以禁用汇编器支持,来得到一个更小的TinyCC可执行文件(C编译器并不依赖汇编器)。

4.1   语法

@waiting ...

4.2   表达式

@waiting ...

4.3   标签

@waiting ...

4.4   指令

@waiting ...

4.5   X86汇编器

@waiting ...

5   TinyCC连接器

5.1   ELF文件生成器

TCC可以在不需要其他连接器的情况下,直接输出重定位的ELF文件(目标文件),可执行ELF文件和动态ELF库。

动态ELF库可以直接输出,但是C编译器并不生成位置独立代码(PIC, Position independent Code)。这意味着TCC生成的动态库无法在进程间分解。

TCC连接器会清楚库里面的无引用对象。这在生成目标文件和库列表时直接跳过,所以指定目标文件和库文件的顺序很重要(对GNU ld也是一样的)。同样也不支持分组选项("--start-group"和"--end-group")。

5.2   ELF文件载入器

TCC无法载入ELF目标文件、静态库(.a文件)和动态库(.so文件)。

5.3   PE-i386文件生成器

TCC的Windows支持本地Win32可执行文件格式(PE-i386)。他可以生成EXE文件(控制台的和GUI的)和DLL文件。

了解在Windows上的使用,查看 tcc-win32.txt

5.4   GNU连接器脚本

因为很多Linux系统的动态库使用GNU ld链接脚本,所以TCC连接器也支持GNU ld脚本的子集。

GROUP和FILE命令是支持的,OUTPUT_FORMAT和TARGET则被忽略。

例如 /usr/lib/libc.so

/* GNU ld script */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )

6   TinyCC内存与边界检查

该功能使用 "-b" 选项激活。

主意指针大小是不变的,而包含边界检查的代码生成与无检查的代码是全兼容的。当有来自无检查代码的指针时,会假设其有效。因此混用的代码之间也可以正常工作。

关于更多方法的信息请关注 http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html

这里是一些捕捉错误的例子:

标准字符串函数处理无效的范围:

{
    char tab[10];
    memset(tab,0,11);
}

对本地和全局数组的越界错误:

{
    int tab[10];
    for(i=0;i<11;i++) {
        sum+=tab[i];
    }
}

由malloc生成的数据的越界错误:

{
    int *tab;
    tab=malloc(20*sizeof(int));
    for(i=0;i<21;i++) {
        sum+=tab4[i];
    }
    free(tab);
}

访问已经释放了的内存:

{
    int *tab;
    tab=malloc(20*sizeof(int));
    free(tab);
    for(i=0;i<20;i++) {
        sum+=tab4[i];
    }
}

二次释放:

{
    int *tab;
    tab=malloc(20*sizeof(int));
    free(tab);
    free(tab);
}

7   libtcc库

libtcc库允许你把TCC作为动态代码生成的后端。

阅读 libtcc.h 了解API。阅读 libtcc_test.c 看简单的例子。

这个主意在于你可以把C字符串直接通过libtcc编译。然后可以存取任意的全局符号。

7.1   libtcc API

TCCState *tcc_new(void)

创建新的TCC编译上下文。

void tcc_delete(TCCState *s)

释放TCC编译上下文。

void tcc_enable_debug(TCCState *s)

在生成代码中添加调试信息。

void tcc_set_error_func(TCCState *s, void *error_opaque, void (*error_func)(void *opaque, const char *msg))

设置发生错误/警告时的回调函数。

int tcc_set_warning(TCCState *s, const char *warning_name, int value)

设置和重设警告。

下面是预处理函数。

int tcc_add_include_path(TCCState *s, const char *pathname)

添加头文件搜索路径。

int tcc_add_sysinclude_path(TCCState *s, const char *pathname)

添加系统头文件搜索路径。

void tcc_define_symbol(TCCState *s, const char *sym, const char *value)

定义预处理器符号 "sym" ,可以添加可选的值。

void tcc_undefine_symbol(TCCState *s, const char *sym)

取消预处理器符号 "sym" 的定义。

如下是编译函数。

int tcc_add_file(TCCState *s, const char *filename)

添加一个文件,可以是C文件、dll、对象、库或者ld脚本。错误返回-1。

int tcc_compile_string(TCCState *s, const char *buf)

编译作为C源码的字符串,错误返回非0。

链接命令。

输出类型,必须在所有编译之前定义:

  1. TCC_OUTPUT_MENORY :输出到内存,缺省值
  2. TCC_OUTPUT_EXE :输出到可执行文件
  3. TCC_OUTPUT_DLL :输出动态库
  4. TCC_OUTPUT_OBJ :输出目标文件
  5. TCC_OUTPUT_PREPROCESS :输出预处理文件(内部使用)

int tcc_set_output_type(TCCState *s, int output_type)

设置输出类型。

可执行文件格式:

  1. TCC_OUTPUT_FORMAT_ELF :输出格式ELF,缺省值
  2. TCC_OUTPUT_FORMAT_BINARY :二进制镜像
  3. TCC_OUTPUT_FORMAT_COFF :COFF

int tcc_add_library_path(TCCState *s, const char *pathname)

等效于 "-Lpath" 选项。

int tcc_add_library(TCCState *s, const char *libraryname)

等同于用 "-lxxx" 选项添加链接库。

int tcc_add_symbol(TCCState *s, const char *name, void *val)

添加符号到编译过的程序。

int tcc_output_file(TCCState *s, const char *filename)

输出可执行文件、库或目标文件,在此之前别调用 tcc_relocate()

int tcc_run(TCCState *s, int argc, char **argv)

链接和运行 main() 函数,并返回值。在此之前别调用 tcc_relocate()

int tcc_relocate(TCCState *s1, void *ptr)

拷贝代码到内存传递给调用者,并做重定位(必须在 tcc_get_symbol() 之前调用)。如果出错返回-1且在ptr是NULL时需要大小。

void *tcc_get_symbol(TCCState *s, const char *name)

返回符号的值或找不到时返回NULL。

void tcc_set_lib_path(TCCState *s, const char *path)

设置运行时的CONFIG_TCCDIR。

7.2   libtcc的例子

tests/libtcc_test.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libtcc.h"

/*这个函数将会被生成的代码所调用*/
int add(int a, int b) {
    return a+b;
}

char my_program[] =
"int fib(int n) {\n"
"    if (n<=2)\n"
"        return 1;n"
"    else\n"
"        return fib(n-1)+fib(n-2);\n"
"}\n"
"int foo(int n) {\n"
"    printf(\"Hello World!\\n);\n"
"    return 0;\n"
"}\n";

int main(int argc, char **argv) {
    TCCState *s;
    int (*func)(int);
    void *mem;
    int size;

    s=tcc_new();
    if (!s) {
        fprintf(stderr, "Could not create tcc state\n");
        exit(1);
    }
    /*如果tcclib.h和libtcc1.a尚未安装,寻找他们*/
    if (argc==2 && !memcmp(argv[1],"lib_path=",9))
        tcc_set_lib_path(s,argv[1]+9);

    /*必须在任何编译之前设置输出类型*/
    tcc_set_output_type(s,TCC_OUTPUT_MEMORY);
    if (tcc_compile_string(s,my_program) == -1)
        return 1;

    /*添加add()函数允许动态生成代码调用,还可以用 tcc_add_dll() 来用。*/
    tcc_add_symbol(s,"add",add);
    /*获取代码大小*/
    size=tcc_relocate(s,NULL);
    if (size== -1)
        return 1;
    /*重定位内存并拷贝代码*/
    mem=malloc(size);
    tcc_relocate(s,mem);
    /*获取入口符号*/
    func=tcc_get_symbol(s,"foo");
    if (!func)
        return 1;
    /*删除状态*/
    tcc_delete(s);
    /*运行代码*/
    func(32);
    free(mem);
    return 0;
}

8   开发者指南

本章给出一些介绍用以了解TCC的工作方式。如果不关心修改TCC的代码,可以直接跳过。

@waiting ...

8.1   文件读取

@waiting ...

8.2   词法(lexer)

@waiting ...

8.4   类型

@waiting ...

8.5   符号

@waiting ...

8.6   段

@waiting ...

8.7   代码生成

8.7.1   介绍

TCC代码生成直接生成连接过的二进制代码。尽管不太常用(查看gcc生成文本汇编代码的例子),但是速度却很快且有些复杂。

TCC代码生成器是基于寄存器的。优化限于表达式级别。表达式的中间表示方式不保存,除非其值在 "value stack" 中。

在x86上,使用了3个临时寄存器。当需要更多寄存器时,一个寄存器被切分到栈上的临时变量中。

8.7.2   数值栈

@waiting ...

8.8   优化

@waiting ...

9   关于本文档

@waiting ...

3
1
分享到:
评论

相关推荐

    TCC(Tiny C Compiler)0.9.26源码 原版和VS工程版

    TCC(Tiny C Compiler)0.9.26源码 原版和VS工程版 VS版: 已经实现VS2008和VS2013 打开即用 可编译 可调试 建议使用VS2008编译

    TCC(Tiny C Compiler)编译器下载

    Tiny C Compiler(简称TCC)是一款轻量级的C语言编译器,由法国程序员Fabrice Bellard开发。它的特点是体积小巧,但编译和链接的速度极快,使其成为快速原型开发、嵌入式系统以及对编译速度有较高要求的项目的理想...

    Tiny_C_Compiler参考手册_-_gashero的Geek前哨_-_CSDN博客_csdn.net_1518480380.mht

    Tiny CC参考手册,格式为PDF,内容丰富,说明很完善还有丰富的例子。

    TCC - Tiny C Compiler ( for linux )

    Tiny C Compiler(TCC) 是一个轻量级高速的C语言编译器。 TCC的编译速度十分快,以至于编译一些大型项目都不需要Makefile文件。 TCC支持ANSI C,大部分的 ISO99 C的新标准和许多GNU C扩展以及C语言和汇编语言混编。...

    TCC(Tiny C Compiler)0.9.26源码 VS版工程

    Tiny C Compiler(简称TCC)是一款小巧而快速的C语言编译器,版本0.9.26。这个源码包特别为Visual Studio环境优化,提供了VS2008和VS2013的支持,使得用户可以直接在这些版本的Visual Studio中打开、编译和调试TCC的...

    tiny c compiler

    TCC compiler sources

    基于TCC-Tiny C Compiler的中文开源C语言编译器设计源码

    该项目是基于TCC-Tiny C Compiler的中文开源C语言编译器设计源码,包含1880个文件,涵盖1216个头文件、270个源文件、136个expect脚本文件、120个BMP图像文件、13个DEF配置文件、9个批处理文件、9个文本文件、8个源...

    TinyCompiler-master_编译原理_TINY-COMPILER_

    在这个项目中,我们将深入探讨一个名为“TINY-COMPILER”的小型编译器的实现,它使用C语言编写,旨在提供一个直观的编译器设计和实现的教学案例。 首先,我们来了解编译器的基本工作流程。编译器通常由以下几个核心...

    Tiny-Compiler:C语言实现的一个Tiny编译器

    Tiny-Compiler是一个基于C语言实现的简单编译器项目,主要目标是将源代码转换为Linux环境下的汇编语言,以便于使用nasm汇编器进行编译和链接。这个项目对于理解编译器的基本原理和工作流程具有很大的教育意义,同时...

    Tiny C Compiler世界上最小的C编译器(实用)

    Tiny C Compiler 世界上最小的C编译器。支持C99标准。小而快!可能还有更小的,但有实用意义的就是它。用2012.10.11源码编译的版本。官方不停的更新源代码,但编译好的最新版本是2009年的。 你希望学习C语言,可以...

    Tiny C Compiler source code 微型C编译器源代码

    ANSI C 兼容编译器。90%兼容GCC编辑器,可内联x86汇编, 适合于研究数据结构与算法和编译器的人员使用。真是小而功能齐全。 官方网站有最新版下载: http://bellard.org/tcc/ 在windows/linux下编译自己都是轻而易举! ...

    TCC(Tiny C Compiler)0.9.26源码+VS工程版

    Tiny C Compiler(简称TCC)是一款小巧而快速的C语言编译器,其0.9.26版本提供了源码及适用于Visual Studio的工程文件,包括VS2008和VS2013的支持,使得用户能够进行编译和调试工作。在本文中,我们将深入探讨TCC的...

    TCC(Tiny C Compiler)0.9.26源码 VS版工程(要分版)

    TCC(Tiny C Compiler)0.9.26源码 VS版工程 已经实现VS2008和VS2013 打开即用 可编译 可调试 建议使用VS2008编译 没分的同学可以去下载无分版: http://download.csdn.net/detail/shen_juntao/8414171

    Tiny4412中文用户手册

    根据提供的信息,本部分将围绕Tiny4412开发板的使用、更新及应用场景进行深入探讨,涵盖嵌入式Linux、C语言、ARM架构等多个技术点。 一、Tiny4412开发板概述 Tiny4412是一款基于ARM9架构的开发板,它为嵌入式Linux...

    nesc手册 tinyos开发语言参考手册

    ### nesc手册 tinyos开发语言参考手册 #### 一、简介与背景 nesc(nesC)是一种基于C语言的扩展编程语言,专为TinyOS设计,以体现其结构概念和执行模型。TinyOS是一个事件驱动的操作系统,主要针对资源极其有限的...

    tiny 6410 开发手册

    《tiny 6410 开发手册》是针对基于Samsung S3C6410处理器的嵌入式系统开发的一份重要参考资料。S3C6410是一款高性能的ARM11架构微处理器,广泛应用于智能手机、平板电脑、数字媒体播放器等设备。这份手册深入浅出地...

    Tiny C Compiler

    Tiny C Compiler(简称TCC)是一款轻量级的C语言编译器,它的设计目标是小巧、快速且易于使用。TCC能够在极短的时间内将C源代码编译成可执行程序,这得益于其独特的即时编译技术。下面将详细讨论TCC的主要特点、工作...

    Tiny-c compiler

    Tiny-C编译器是一款小型但功能完备的C语言编译器,由开发者纯手工编写,没有依赖于常见的词法分析工具Yacc(也称为Bison)和语法分析工具lex(也称为Flex)。这一特点使得Tiny-C编译器的源代码更易理解和维护,同时...

    RTX51 TINY 2.02 中文手册

    RTX51 TINY 2.02 中文手册知识点总结 本文档对 KEIL 公司的 RTX51 TINY 2.02 版实时操作系统内核进行了详细的介绍和说明。该手册主要面向开发者和工程师,旨在帮助他们快速了解和掌握 RTX51 TINY 2.02 的功能和使用...

Global site tag (gtag.js) - Google Analytics