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 }
hello.i

該程序依然是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
hello.s

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都實現了編譯系統的所有功能,我們用編譯驅動程序直接就可以實現源程序到目標文件的轉化。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM