[转载]LCC编译器的源程序分析(3)选择不同的目标代码接口

LCC 里,最重要的一个特征是可以输出不同的目标代码。比如同一个 C 程序,可以生成 MIPS X86 等汇编代码,只需要选择不同的目标参数。这里只分析生成 X86 的代码,所以命令行的参数如下:
rcc.exe -target=x86/nasm hello.i hello.asm
参数 -target=x86/nasm 是让 C 编译器选择生成 X86 NASM 汇编代码。
参数 hello.i 是前面已经介绍的中间文件,它是经过预处理的。
参数 hello.asm 是生成的目标文件。
 
C 编译的入口函数是 main ,它在文件 main.c 里,定义如下:
//
//C 编译器入口。
// 蔡军生  2007/05/13 深圳
//
int main(int argc, char *argv[])
 
main 函数开始里,就是处理参数的代码,如下:
#001 int main(int argc, char *argv[])
#002 {
#003  int i, j;
#004 
#005  for (i = argc - 1; i > 0; i--)
#006  {   
#007         if (strncmp(argv[i], "-target=", 8) == 0)
#008         {
#009               break;
#010         }   
#011  }
#012 
#013  if (i > 0)
#014  {
#015         char *s = strchr(argv[i], '//');
#016         if (s != NULL)
#017         {
#018               *s = '/';
#019         }   
#020 
#021         for (j = 0; bindings[j].name && bindings[j].ir; j++)
#022         {
#023               if (strcmp(&argv[i][8], bindings[j].name) == 0)
#024               {
#025                    IR = bindings[j].ir;
#026                    break;
#027               }
#028         }
#029 
#030         if (s != NULL)
#031         {
#032               *s = '//';
#033         }   
#034  }
#035  
#036  if (!IR)
#037  {
#038         fprint(stderr, "%s: unknown target", argv[0]);
#039         if (i > 0)
#040         {
#041               fprint(stderr, " `%s'", &argv[i][8]);
#042         }   
#043 
#044         fprint(stderr, "; must specify one of/n");
#045 
#046         for (i = 0; bindings[i].name; i++)
#047         {
#048               fprint(stderr, "/t-target=%s/n", bindings[i].name);
#049         }   
#050 
#051         exit(EXIT_FAILURE);
#052  }
 
程序的第 5 行到第 11 行是找到目标代码的参数,也就是识别 -target= 参数。如果找到就跳出循环。
程序的第 13 行到第 34 行是找到相应的生成目标代码的接口。 C 编译器已经定义好可以生成代码的数组,因此这里只需要简单地比较一下名称,就可以找到相应的目标代码的接口了。接口定义的结构如下:
typedef struct binding {
 char *name;
 Interface *ir;
} Binding;
name 保存目标代码的名称, ir 保存了接口。而接口定义如下:
#001 typedef struct interface {
#002  Metrics charmetric;
#003  Metrics shortmetric;
#004  Metrics intmetric;
#005  Metrics longmetric;
#006  Metrics longlongmetric;
#007  Metrics floatmetric;
#008  Metrics doublemetric;
#009  Metrics longdoublemetric;
#010  Metrics ptrmetric;
#011  Metrics structmetric;
#012  unsigned little_endian:1;
#013  unsigned mulops_calls:1;
#014  unsigned wants_callb:1;
#015  unsigned wants_argb:1;
#016  unsigned left_to_right:1;
#017  unsigned wants_dag:1;
#018  unsigned unsigned_char:1;
#019 void (*address)(Symbol p, Symbol q, long n);
#020 void (*blockbeg)(Env *);
#021 void (*blockend)(Env *);
#022 void (*defaddress)(Symbol);
#023 void (*defconst) (int suffix, int size, Value v);
#024 void (*defstring)(int n, char *s);
#025 void (*defsymbol)(Symbol);
#026 void (*emit)    (Node);
#027 void (*export)(Symbol);
#028 void (*function)(Symbol, Symbol[], Symbol[], int);
#029 Node (*gen)     (Node);
#030 void (*global)(Symbol);
#031 void (*import)(Symbol);
#032 void (*local)(Symbol);
#033 void (*progbeg)(int argc, char *argv[]);
#034 void (*progend)(void);
#035 void (*segment)(int);
#036 void (*space)(int);
#037 void (*stabblock)(int, int, Symbol*);
#038 void (*stabend) (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
#039 void (*stabfend) (Symbol, int);
#040 void (*stabinit) (char *, int, char *[]);
#041 void (*stabline) (Coordinate *);
#042  void (*stabsym) (Symbol);
#043 void (*stabtype) (Symbol);
#044  Xinterface x;
#045 } Interface;
接口定义了输出汇编目标代码需要的函数和数据成员。以后再一个函数一个函数地介绍。
继续分析 main 函数里,第 36 行到第 52 行是找不到生成目标代码接口的出错处理。
命令行的参数是 -target=x86/nasm ,所以找到的接口,就是 x86/name 的接口,它保存在 IR 全局变量里。
            到这里,就分析完成选择不同的目标代码生成接口了。 

 

你可能感兴趣的:(汇编,struct,interface,编译器,binding,X86)