5分钟理解编译系统

  本文以一个C语言版的hello world例子阐述编译系统四个阶段的工作内容。源程序hello.c如下:

#include <stdio.h>

int main() {
    printf("hello world!\n");
}

  作为一个精通各种语言的hello world的程序员,我相信你一定看得懂上面这段C代码。总所周知,像C语言这类的编译语言,都是将人类可读的源代码“编译”成机器能识别的“机器代码”,然后方能执行的。而我们通常所说的“编译”,实际上是指的是编译系统,一共包含4个阶段。即:预处理,编译,汇编,链接。而正是这四个阶段所需要的预处理器、编译器、汇编器、链接器构成了编译系统(compilation system)。下图是hello.c经过“编译”成为可执行的目标程序的过程示意图,接下来,将围绕此图阐述各个阶段的工作内容。

1. 预处理阶段

  预处理器(cpp)根据以字符#号开头的命令,修改原始的c程序。比如hello.c中的第一行#include <stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中,结果得到了另一个C程序,通常是以.i为扩展名。在Linux下我们用GCC命令:

gcc -E hello.c -o hello.i

得到一个hello.i文件,然后查看文件内容如下:

  1 # 1 "hello.c"
  2 # 1 "<built-in>"
  3 # 1 "<command-line>"
  4 # 1 "/usr/include/stdc-predef.h" 1 3 4
  5 # 1 "<command-line>" 2
  6 # 1 "hello.c"
  7 # 1 "/usr/include/stdio.h" 1 3 4
  8 # 27 "/usr/include/stdio.h" 3 4
  9 # 1 "/usr/include/features.h" 1 3 4
 10 # 375 "/usr/include/features.h" 3 4
 11 # 1 "/usr/include/sys/cdefs.h" 1 3 4
 12 # 392 "/usr/include/sys/cdefs.h" 3 4
 13 # 1 "/usr/include/bits/wordsize.h" 1 3 4
 14 # 393 "/usr/include/sys/cdefs.h" 2 3 4
 15 # 376 "/usr/include/features.h" 2 3 4
 16 # 399 "/usr/include/features.h" 3 4
 17 # 1 "/usr/include/gnu/stubs.h" 1 3 4
 18 # 10 "/usr/include/gnu/stubs.h" 3 4
 19 # 1 "/usr/include/gnu/stubs-64.h" 1 3 4
 20 # 11 "/usr/include/gnu/stubs.h" 2 3 4
 21 # 400 "/usr/include/features.h" 2 3 4
 22 # 28 "/usr/include/stdio.h" 2 3 4
 23 
 24 
 25 
 26 
 27 
 28 # 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
 29 # 212 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 3 4
 30 typedef long unsigned int size_t;
 31 # 34 "/usr/include/stdio.h" 2 3 4
 32 
 33 # 1 "/usr/include/bits/types.h" 1 3 4
 34 # 27 "/usr/include/bits/types.h" 3 4
 35 # 1 "/usr/include/bits/wordsize.h" 1 3 4
 36 # 28 "/usr/include/bits/types.h" 2 3 4
 37 
 38 
 39 typedef unsigned char __u_char;
 40 typedef unsigned short int __u_short;
 41 typedef unsigned int __u_int;
 42 typedef unsigned long int __u_long;
 43 
 44 
 45 typedef signed char __int8_t;
 46 typedef unsigned char __uint8_t;
 47 typedef signed short int __int16_t;
 48 typedef unsigned short int __uint16_t;
 49 typedef signed int __int32_t;
 50 typedef unsigned int __uint32_t;
 51 
 52 typedef signed long int __int64_t;
 53 typedef unsigned long int __uint64_t;
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 typedef long int __quad_t;
 62 typedef unsigned long int __u_quad_t;
 63 # 130 "/usr/include/bits/types.h" 3 4
 64 # 1 "/usr/include/bits/typesizes.h" 1 3 4
 65 # 131 "/usr/include/bits/types.h" 2 3 4
 66 
 67 
 68 typedef unsigned long int __dev_t;
 69 typedef unsigned int __uid_t;
 70 typedef unsigned int __gid_t;
 71 typedef unsigned long int __ino_t;
 72 typedef unsigned long int __ino64_t;
 73 typedef unsigned int __mode_t;
 74 typedef unsigned long int __nlink_t;
 75 typedef long int __off_t;
 76 typedef long int __off64_t;
 77 typedef int __pid_t;
 78 typedef struct { int __val[2]; } __fsid_t;
 79 typedef long int __clock_t;
 80 typedef unsigned long int __rlim_t;
 81 typedef unsigned long int __rlim64_t;
 82 typedef unsigned int __id_t;
 83 typedef long int __time_t;
 84 typedef unsigned int __useconds_t;
 85 typedef long int __suseconds_t;
 86 
 87 typedef int __daddr_t;
 88 typedef int __key_t;
 89 
 90 
 91 typedef int __clockid_t;
 92 
 93 
 94 typedef void * __timer_t;
 95 
 96 
 97 typedef long int __blksize_t;
 98 
 99 
100 
101 
102 typedef long int __blkcnt_t;
103 typedef long int __blkcnt64_t;
104 
105 
106 typedef unsigned long int __fsblkcnt_t;
107 typedef unsigned long int __fsblkcnt64_t;
108 
109 
110 typedef unsigned long int __fsfilcnt_t;
111 typedef unsigned long int __fsfilcnt64_t;
112 
113 
114 typedef long int __fsword_t;
115 
116 typedef long int __ssize_t;
117 
118 
119 typedef long int __syscall_slong_t;
120 
121 typedef unsigned long int __syscall_ulong_t;
122 
123 
124 
125 typedef __off64_t __loff_t;
126 typedef __quad_t *__qaddr_t;
127 typedef char *__caddr_t;
128 
129 
130 typedef long int __intptr_t;
131 
132 
133 typedef unsigned int __socklen_t;
134 # 36 "/usr/include/stdio.h" 2 3 4
135 # 44 "/usr/include/stdio.h" 3 4
136 struct _IO_FILE;
137 
138 
139 
140 typedef struct _IO_FILE FILE;
141 
142 
143 
144 
145 
146 # 64 "/usr/include/stdio.h" 3 4
147 typedef struct _IO_FILE __FILE;
148 # 74 "/usr/include/stdio.h" 3 4
149 # 1 "/usr/include/libio.h" 1 3 4
150 # 32 "/usr/include/libio.h" 3 4
151 # 1 "/usr/include/_G_config.h" 1 3 4
152 # 15 "/usr/include/_G_config.h" 3 4
153 # 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
154 # 16 "/usr/include/_G_config.h" 2 3 4
155 
156 
157 
158 
159 # 1 "/usr/include/wchar.h" 1 3 4
160 # 82 "/usr/include/wchar.h" 3 4
161 typedef struct
162 {
163   int __count;
164   union
165   {
166 
167     unsigned int __wch;
168 
169 
170 
171     char __wchb[4];
172   } __value;
173 } __mbstate_t;
174 # 21 "/usr/include/_G_config.h" 2 3 4
175 typedef struct
176 {
177   __off_t __pos;
178   __mbstate_t __state;
179 } _G_fpos_t;
180 typedef struct
181 {
182   __off64_t __pos;
183   __mbstate_t __state;
184 } _G_fpos64_t;
185 # 33 "/usr/include/libio.h" 2 3 4
186 # 50 "/usr/include/libio.h" 3 4
187 # 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stdarg.h" 1 3 4
188 # 40 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stdarg.h" 3 4
189 typedef __builtin_va_list __gnuc_va_list;
190 # 51 "/usr/include/libio.h" 2 3 4
191 # 145 "/usr/include/libio.h" 3 4
192 struct _IO_jump_t; struct _IO_FILE;
193 # 155 "/usr/include/libio.h" 3 4
194 typedef void _IO_lock_t;
195 
196 
197 
198 
199 
200 struct _IO_marker {
201   struct _IO_marker *_next;
202   struct _IO_FILE *_sbuf;
203 
204 
205 
206   int _pos;
207 # 178 "/usr/include/libio.h" 3 4
208 };
209 
210 
211 enum __codecvt_result
212 {
213   __codecvt_ok,
214   __codecvt_partial,
215   __codecvt_error,
216   __codecvt_noconv
217 };
218 # 246 "/usr/include/libio.h" 3 4
219 struct _IO_FILE {
220   int _flags;
221 
222 
223 
224 
225   char* _IO_read_ptr;
226   char* _IO_read_end;
227   char* _IO_read_base;
228   char* _IO_write_base;
229   char* _IO_write_ptr;
230   char* _IO_write_end;
231   char* _IO_buf_base;
232   char* _IO_buf_end;
233 
234   char *_IO_save_base;
235   char *_IO_backup_base;
236   char *_IO_save_end;
237 
238   struct _IO_marker *_markers;
239 
240   struct _IO_FILE *_chain;
241 
242   int _fileno;
243 
244 
245 
246   int _flags2;
247 
248   __off_t _old_offset;
249 
250 
251 
252   unsigned short _cur_column;
253   signed char _vtable_offset;
254   char _shortbuf[1];
255 
256 
257 
258   _IO_lock_t *_lock;
259 # 294 "/usr/include/libio.h" 3 4
260   __off64_t _offset;
261 # 303 "/usr/include/libio.h" 3 4
262   void *__pad1;
263   void *__pad2;
264   void *__pad3;
265   void *__pad4;
266   size_t __pad5;
267 
268   int _mode;
269 
270   char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
271 
272 };
273 
274 
275 typedef struct _IO_FILE _IO_FILE;
276 
277 
278 struct _IO_FILE_plus;
279 
280 extern struct _IO_FILE_plus _IO_2_1_stdin_;
281 extern struct _IO_FILE_plus _IO_2_1_stdout_;
282 extern struct _IO_FILE_plus _IO_2_1_stderr_;
283 # 339 "/usr/include/libio.h" 3 4
284 typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);
285 
286 
287 
288 
289 
290 
291 
292 typedef __ssize_t __io_write_fn (void *__cookie, const char *__buf,
293      size_t __n);
294 
295 
296 
297 
298 
299 
300 
301 typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);
302 
303 
304 typedef int __io_close_fn (void *__cookie);
305 # 391 "/usr/include/libio.h" 3 4
306 extern int __underflow (_IO_FILE *);
307 extern int __uflow (_IO_FILE *);
308 extern int __overflow (_IO_FILE *, int);
309 # 435 "/usr/include/libio.h" 3 4
310 extern int _IO_getc (_IO_FILE *__fp);
311 extern int _IO_putc (int __c, _IO_FILE *__fp);
312 extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));
313 extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));
314 
315 extern int _IO_peekc_locked (_IO_FILE *__fp);
316 
317 
318 
319 
320 
321 extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
322 extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
323 extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
324 # 465 "/usr/include/libio.h" 3 4
325 extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
326    __gnuc_va_list, int *__restrict);
327 extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
328     __gnuc_va_list);
329 extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);
330 extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);
331 
332 extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);
333 extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);
334 
335 extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
336 # 75 "/usr/include/stdio.h" 2 3 4
337 
338 
339 
340 
341 typedef __gnuc_va_list va_list;
342 # 90 "/usr/include/stdio.h" 3 4
343 typedef __off_t off_t;
344 # 102 "/usr/include/stdio.h" 3 4
345 typedef __ssize_t ssize_t;
346 
347 
348 
349 
350 
351 
352 
353 typedef _G_fpos_t fpos_t;
354 
355 
356 
357 
358 # 164 "/usr/include/stdio.h" 3 4
359 # 1 "/usr/include/bits/stdio_lim.h" 1 3 4
360 # 165 "/usr/include/stdio.h" 2 3 4
361 
362 
363 
364 extern struct _IO_FILE *stdin;
365 extern struct _IO_FILE *stdout;
366 extern struct _IO_FILE *stderr;
367 
368 
369 
370 
371 
372 
373 
374 extern int remove (const char *__filename) __attribute__ ((__nothrow__ , __leaf__));
375 
376 extern int rename (const char *__old, const char *__new) __attribute__ ((__nothrow__ , __leaf__));
377 
378 
379 
380 
381 extern int renameat (int __oldfd, const char *__old, int __newfd,
382        const char *__new) __attribute__ ((__nothrow__ , __leaf__));
383 
384 
385 
386 
387 
388 
389 
390 
391 extern FILE *tmpfile (void) ;
392 # 209 "/usr/include/stdio.h" 3 4
393 extern char *tmpnam (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
394 
395 
396 
397 
398 
399 extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
400 # 227 "/usr/include/stdio.h" 3 4
401 extern char *tempnam (const char *__dir, const char *__pfx)
402      __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ;
403 
404 
405 
406 
407 
408 
409 
410 
411 extern int fclose (FILE *__stream);
412 
413 
414 
415 
416 extern int fflush (FILE *__stream);
417 
418 # 252 "/usr/include/stdio.h" 3 4
419 extern int fflush_unlocked (FILE *__stream);
420 # 266 "/usr/include/stdio.h" 3 4
421 
422 
423 
424 
425 
426 
427 extern FILE *fopen (const char *__restrict __filename,
428       const char *__restrict __modes) ;
429 
430 
431 
432 
433 extern FILE *freopen (const char *__restrict __filename,
434         const char *__restrict __modes,
435         FILE *__restrict __stream) ;
436 # 295 "/usr/include/stdio.h" 3 4
437 
438 # 306 "/usr/include/stdio.h" 3 4
439 extern FILE *fdopen (int __fd, const char *__modes) __attribute__ ((__nothrow__ , __leaf__)) ;
440 # 319 "/usr/include/stdio.h" 3 4
441 extern FILE *fmemopen (void *__s, size_t __len, const char *__modes)
442   __attribute__ ((__nothrow__ , __leaf__)) ;
443 
444 
445 
446 
447 extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__ , __leaf__)) ;
448 
449 
450 
451 
452 
453 
454 extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__ , __leaf__));
455 
456 
457 
458 extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
459       int __modes, size_t __n) __attribute__ ((__nothrow__ , __leaf__));
460 
461 
462 
463 
464 
465 extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
466          size_t __size) __attribute__ ((__nothrow__ , __leaf__));
467 
468 
469 extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
470 
471 
472 
473 
474 
475 
476 
477 
478 extern int fprintf (FILE *__restrict __stream,
479       const char *__restrict __format, ...);
480 
481 
482 
483 
484 extern int printf (const char *__restrict __format, ...);
485 
486 extern int sprintf (char *__restrict __s,
487       const char *__restrict __format, ...) __attribute__ ((__nothrow__));
488 
489 
490 
491 
492 
493 extern int vfprintf (FILE *__restrict __s, const char *__restrict __format,
494        __gnuc_va_list __arg);
495 
496 
497 
498 
499 extern int vprintf (const char *__restrict __format, __gnuc_va_list __arg);
500 
501 extern int vsprintf (char *__restrict __s, const char *__restrict __format,
502        __gnuc_va_list __arg) __attribute__ ((__nothrow__));
503 
504 
505 
506 
507 
508 extern int snprintf (char *__restrict __s, size_t __maxlen,
509        const char *__restrict __format, ...)
510      __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 4)));
511 
512 extern int vsnprintf (char *__restrict __s, size_t __maxlen,
513         const char *__restrict __format, __gnuc_va_list __arg)
514      __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 0)));
515 
516 # 412 "/usr/include/stdio.h" 3 4
517 extern int vdprintf (int __fd, const char *__restrict __fmt,
518        __gnuc_va_list __arg)
519      __attribute__ ((__format__ (__printf__, 2, 0)));
520 extern int dprintf (int __fd, const char *__restrict __fmt, ...)
521      __attribute__ ((__format__ (__printf__, 2, 3)));
522 
523 
524 
525 
526 
527 
528 
529 
530 extern int fscanf (FILE *__restrict __stream,
531      const char *__restrict __format, ...) ;
532 
533 
534 
535 
536 extern int scanf (const char *__restrict __format, ...) ;
537 
538 extern int sscanf (const char *__restrict __s,
539      const char *__restrict __format, ...) __attribute__ ((__nothrow__ , __leaf__));
540 # 443 "/usr/include/stdio.h" 3 4
541 extern int fscanf (FILE *__restrict __stream, const char *__restrict __format, ...) __asm__ ("" "__isoc99_fscanf")
542 
543                                ;
544 extern int scanf (const char *__restrict __format, ...) __asm__ ("" "__isoc99_scanf")
545                               ;
546 extern int sscanf (const char *__restrict __s, const char *__restrict __format, ...) __asm__ ("" "__isoc99_sscanf") __attribute__ ((__nothrow__ , __leaf__))
547 
548                       ;
549 # 463 "/usr/include/stdio.h" 3 4
550 
551 
552 
553 
554 
555 
556 
557 
558 extern int vfscanf (FILE *__restrict __s, const char *__restrict __format,
559       __gnuc_va_list __arg)
560      __attribute__ ((__format__ (__scanf__, 2, 0))) ;
561 
562 
563 
564 
565 
566 extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg)
567      __attribute__ ((__format__ (__scanf__, 1, 0))) ;
568 
569 
570 extern int vsscanf (const char *__restrict __s,
571       const char *__restrict __format, __gnuc_va_list __arg)
572      __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
573 # 494 "/usr/include/stdio.h" 3 4
574 extern int vfscanf (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vfscanf")
575 
576 
577 
578      __attribute__ ((__format__ (__scanf__, 2, 0))) ;
579 extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vscanf")
580 
581      __attribute__ ((__format__ (__scanf__, 1, 0))) ;
582 extern int vsscanf (const char *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vsscanf") __attribute__ ((__nothrow__ , __leaf__))
583 
584 
585 
586      __attribute__ ((__format__ (__scanf__, 2, 0)));
587 # 522 "/usr/include/stdio.h" 3 4
588 
589 
590 
591 
592 
593 
594 
595 
596 
597 extern int fgetc (FILE *__stream);
598 extern int getc (FILE *__stream);
599 
600 
601 
602 
603 
604 extern int getchar (void);
605 
606 # 550 "/usr/include/stdio.h" 3 4
607 extern int getc_unlocked (FILE *__stream);
608 extern int getchar_unlocked (void);
609 # 561 "/usr/include/stdio.h" 3 4
610 extern int fgetc_unlocked (FILE *__stream);
611 
612 
613 
614 
615 
616 
617 
618 
619 
620 
621 
622 extern int fputc (int __c, FILE *__stream);
623 extern int putc (int __c, FILE *__stream);
624 
625 
626 
627 
628 
629 extern int putchar (int __c);
630 
631 # 594 "/usr/include/stdio.h" 3 4
632 extern int fputc_unlocked (int __c, FILE *__stream);
633 
634 
635 
636 
637 
638 
639 
640 extern int putc_unlocked (int __c, FILE *__stream);
641 extern int putchar_unlocked (int __c);
642 
643 
644 
645 
646 
647 
648 extern int getw (FILE *__stream);
649 
650 
651 extern int putw (int __w, FILE *__stream);
652 
653 
654 
655 
656 
657 
658 
659 
660 extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
661      ;
662 # 638 "/usr/include/stdio.h" 3 4
663 extern char *gets (char *__s) __attribute__ ((__deprecated__));
664 
665 
666 # 665 "/usr/include/stdio.h" 3 4
667 extern __ssize_t __getdelim (char **__restrict __lineptr,
668           size_t *__restrict __n, int __delimiter,
669           FILE *__restrict __stream) ;
670 extern __ssize_t getdelim (char **__restrict __lineptr,
671         size_t *__restrict __n, int __delimiter,
672         FILE *__restrict __stream) ;
673 
674 
675 
676 
677 
678 
679 
680 extern __ssize_t getline (char **__restrict __lineptr,
681        size_t *__restrict __n,
682        FILE *__restrict __stream) ;
683 
684 
685 
686 
687 
688 
689 
690 
691 extern int fputs (const char *__restrict __s, FILE *__restrict __stream);
692 
693 
694 
695 
696 
697 extern int puts (const char *__s);
698 
699 
700 
701 
702 
703 
704 extern int ungetc (int __c, FILE *__stream);
705 
706 
707 
708 
709 
710 
711 extern size_t fread (void *__restrict __ptr, size_t __size,
712        size_t __n, FILE *__restrict __stream) ;
713 
714 
715 
716 
717 extern size_t fwrite (const void *__restrict __ptr, size_t __size,
718         size_t __n, FILE *__restrict __s);
719 
720 # 737 "/usr/include/stdio.h" 3 4
721 extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,
722          size_t __n, FILE *__restrict __stream) ;
723 extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size,
724           size_t __n, FILE *__restrict __stream);
725 
726 
727 
728 
729 
730 
731 
732 
733 extern int fseek (FILE *__stream, long int __off, int __whence);
734 
735 
736 
737 
738 extern long int ftell (FILE *__stream) ;
739 
740 
741 
742 
743 extern void rewind (FILE *__stream);
744 
745 # 773 "/usr/include/stdio.h" 3 4
746 extern int fseeko (FILE *__stream, __off_t __off, int __whence);
747 
748 
749 
750 
751 extern __off_t ftello (FILE *__stream) ;
752 # 792 "/usr/include/stdio.h" 3 4
753 
754 
755 
756 
757 
758 
759 extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
760 
761 
762 
763 
764 extern int fsetpos (FILE *__stream, const fpos_t *__pos);
765 # 815 "/usr/include/stdio.h" 3 4
766 
767 # 824 "/usr/include/stdio.h" 3 4
768 
769 
770 extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
771 
772 extern int feof (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
773 
774 extern int ferror (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
775 
776 
777 
778 
779 extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
780 extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
781 extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
782 
783 
784 
785 
786 
787 
788 
789 
790 extern void perror (const char *__s);
791 
792 
793 
794 
795 
796 
797 # 1 "/usr/include/bits/sys_errlist.h" 1 3 4
798 # 26 "/usr/include/bits/sys_errlist.h" 3 4
799 extern int sys_nerr;
800 extern const char *const sys_errlist[];
801 # 854 "/usr/include/stdio.h" 2 3 4
802 
803 
804 
805 
806 extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
807 
808 
809 
810 
811 extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
812 # 873 "/usr/include/stdio.h" 3 4
813 extern FILE *popen (const char *__command, const char *__modes) ;
814 
815 
816 
817 
818 
819 extern int pclose (FILE *__stream);
820 
821 
822 
823 
824 
825 extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
826 # 913 "/usr/include/stdio.h" 3 4
827 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
828 
829 
830 
831 extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
832 
833 
834 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
835 # 943 "/usr/include/stdio.h" 3 4
836 
837 # 2 "hello.c" 2
838 
839 int main() {
840     printf("hello world!\n");
841 }

该程序依然是C语言程序,只不过多了头文件stdio.h的内容。

2. 编译阶段

  编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言中每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令。其实汇编语言是非常有用的,它为所有的高级语言提供了一种通用的输出语言。比如C编译器和Fortran编译器产生的输出文件用的都是一样的汇编语言。在Linux下,我们用命令:

gcc -S hello.i -o hello.s

得到一个hello.s汇编程序,内容如下:

    .file    "hello.c"
    .section    .rodata
.LC0:
    .string    "hello world!"
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $.LC0, %edi
    call    puts
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-11)"
    .section    .note.GNU-stack,"",@progbits

3. 汇编阶段

  汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可定位目标程序的格式,并将结果保存在目标文件hello.o中,hello.o是一个二进制文件,它的字节编码是“机器语言指令”而不是“字符”,所以,我们用文本编辑器打开hello.o文件看到是回事一堆乱码。使用gcc命令:

gcc -c hello.s -o hello.o

将得到hello.o文件,用vim打开看一下是如下乱码:

4. 链接阶段

  我们注意到,hello.c中有一个printf函数,它是每个C编译器都会提供的标准库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器(ld)就是负责处理这种合并。最后得到hello文件,一个可执行目标文件(可执行文件),可被加载到内存中,由系统执行。使用命令:

gcc hello.o -o hello

 得到hello文件,内容如下:

  自此,编译系统的整个过程大致如此。总结一下,从源程序到目标文件(可执行文件)的转化是通过编译系统完成的,编译系统包含四个阶段:预处理,编译,汇编,链接。一般的编译驱动程序如GCC都实现了编译系统的所有功能,我们用编译驱动程序直接就可以实现源程序到目标文件的转化。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小勇DW3

唯一索引的一种使用情景【有则U无则I】

这个知识点是最近一位面试老师问我的,当时对这种方法不了解,所以只能说那个中效率低的方法了,也就是先进性select判断,然后在执行更新或者插入操作,显然这种是很...

1124
来自专栏杨建荣的学习笔记

MySQL创建表失败的问题

今天有一个朋友问我一个MySQL的建表问题,问题的现象是创建表失败,根据他的反馈,问题比较奇怪, CREATE TABLE XXX ..此处省略260多个字...

3777
来自专栏与神兽党一起成长

修改MySQL varchar类型字段的排序规则

记录一个在工作中遇到的问题,也不算是问题,为的是找一种简便的方法批量修改数据表字段的排序规则,在MySQL中叫collation,常常和编码CHARACTER一...

2313
来自专栏Danny的专栏

【MyBatis框架点滴】——mybatis插入数据返回主键(mysql、oracle)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

1042
来自专栏java达人

百万级数据查询优化(数据库)

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 2.应尽量避免在 where 子句中对字段进行 n...

2469
来自专栏码农分享

SQL Server 多表数据增量获取和发布 2.3

812
来自专栏坚毅的PHP

mysql DUPLICATE KEY UPDATE 问题

DUPLICATE KEY UPDATE batch执行时出死锁错误 背景知识 一、 mysql  insert 与 duplicate key: 典型的插入语...

4445
来自专栏程序猿

从0学习MySQL系列(三)概念篇

概要 ---- 在篇文章中提过:概念:数据库管理系统(Database Management System)一些语法的汇总点。 ...

3095
来自专栏王磊的博客

mysql default unix_timestamp(now())

按照mssql的创建方式,去创建mysql的默认值时间戳是不能被允许的,例如下面代码: CREATE TABLE USERINFO( CREATETIME ...

3628
来自专栏Java帮帮-微信公众号-技术文章全总结

Oracle应用实战三——表+序列

创建表空间 表空间? ORACLE数据库的逻辑单元。 数据库---表空间 一个表空间可以与多个数据文件(物理结构)关联 一个数据库下可以建立多个表空间...

3084

扫码关注云+社区