gccコマンドは呼び出し屋さん gccコマンドの裏側
スポンサーリンク
このドキュメントの内容は、以下の通りです。
たまたまgccの話をすることになったので、忘れかけていたことを思い出したので、記事として残しておきます。普段、なにげなく実行しているcc/gccコマンドさんですが、 gcc がなんでもかんでもやっているのではなく、 gcc は、他のプログラムを呼び出して、処理をしてもらっています。
Cプログラムのコンパイルの過程で、
プリプロセッサディレクティブを処理し、
アセンブリコードへ変換し、
機械語へ変換し、
オブジェクトを結合します。
gcc は、中間言語に変換していた気がするけど、
おおざっぱに言えば、gccを実行すると、その裏側では、以下のコマンドによって、こんな順番で処理される。
- cpp
- cc1
- as
- ld
たとえば、 include や define です。
読み込んでいる include をすべて展開し、マクロを展開していきます。
gcc -E foo.c でプリプロセス後の結果を得られます。
たとえば、こんな単純な a.c というソースファイルを用意する。
#include <stdio.h> #include <stdlib.h> #define STR "hello" int main (int argc, char *argv[]) { (void) printf ("%s\n", STR); exit (EXIT_SUCCESS); }
cpp コマンドによる処理
Cプロセッサディレクティブを、 cpp コマンドで処理する。
cpp a.c -o a.i
できあがった、a.i は、以下のような内容になる。
include で指定されたヘッダファイルなどが読み込まれていることがわかる。
# 1 "a.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "a.c" # 1 "/usr/include/stdio.h" 1 3 4 # 43 "/usr/include/stdio.h" 3 4 # 1 "/usr/include/sys/cdefs.h" 1 3 4 # 44 "/usr/include/stdio.h" 2 3 4 # 1 "/usr/include/sys/_null.h" 1 3 4 # 45 "/usr/include/stdio.h" 2 3 4 # 1 "/usr/include/sys/_types.h" 1 3 4 # 33 "/usr/include/sys/_types.h" 3 4 # 1 "/usr/include/machine/_types.h" 1 3 4 # 51 "/usr/include/machine/_types.h" 3 4 typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; typedef int __attribute__((__mode__(__DI__))) __int64_t; typedef unsigned int __attribute__((__mode__(__DI__))) __uint64_t; # 76 "/usr/include/machine/_types.h" 3 4 typedef unsigned long __clock_t; typedef unsigned int __cpumask_t; typedef __int32_t __critical_t; typedef long double __double_t; typedef long double __float_t; typedef __int32_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int32_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int32_t __ptrdiff_t; typedef __int32_t __register_t; typedef __int32_t __segsz_t; typedef __uint32_t __size_t; typedef __int32_t __ssize_t; typedef __int32_t __time_t; typedef __uint32_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint32_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint32_t __u_register_t; typedef __uint32_t __vm_offset_t; typedef __int64_t __vm_ooffset_t; typedef __uint32_t __vm_paddr_t; typedef __uint64_t __vm_pindex_t; typedef __uint32_t __vm_size_t; typedef __builtin_va_list __va_list; typedef __va_list __gnuc_va_list; # 34 "/usr/include/sys/_types.h" 2 3 4 typedef __uint32_t __blksize_t; typedef __int64_t __blkcnt_t; typedef __int32_t __clockid_t; typedef __uint32_t __fflags_t; typedef __uint64_t __fsblkcnt_t; typedef __uint64_t __fsfilcnt_t; typedef __uint32_t __gid_t; typedef __int64_t __id_t; typedef __uint32_t __ino_t; typedef long __key_t; typedef __int32_t __lwpid_t; typedef __uint16_t __mode_t; typedef int __accmode_t; typedef int __nl_item; typedef __uint16_t __nlink_t; typedef __int64_t __off_t; typedef __int32_t __pid_t; typedef __int64_t __rlim_t; typedef __uint8_t __sa_family_t; typedef __uint32_t __socklen_t; typedef long __suseconds_t; typedef struct __timer *__timer_t; typedef struct __mq *__mqd_t; typedef __uint32_t __uid_t; typedef unsigned int __useconds_t; typedef int __cpuwhich_t; typedef int __cpulevel_t; typedef int __cpusetid_t; # 87 "/usr/include/sys/_types.h" 3 4 typedef int __ct_rune_t; typedef __ct_rune_t __rune_t; typedef __ct_rune_t __wchar_t; typedef __ct_rune_t __wint_t; typedef __uint32_t __dev_t; typedef __uint32_t __fixpt_t; typedef union { char __mbstate8[128]; __int64_t _mbstateL; } __mbstate_t; # 46 "/usr/include/stdio.h" 2 3 4 typedef __off_t fpos_t; typedef __size_t size_t; typedef __off_t off_t; typedef __ssize_t ssize_t; typedef __va_list va_list; # 81 "/usr/include/stdio.h" 3 4 struct __sbuf { unsigned char *_base; int _size; }; # 114 "/usr/include/stdio.h" 3 4 typedef struct __sFILE { unsigned char *_p; int _r; int _w; short _flags; short _file; struct __sbuf _bf; int _lbfsize; void *_cookie; int (*_close)(void *); int (*_read)(void *, char *, int); fpos_t (*_seek)(void *, fpos_t, int); int (*_write)(void *, const char *, int); struct __sbuf _ub; unsigned char *_up; int _ur; unsigned char _ubuf[3]; unsigned char _nbuf[1]; struct __sbuf _lb; int _blksize; fpos_t _offset; struct pthread_mutex *_fl_mutex; struct pthread *_fl_owner; int _fl_count; int _orientation; __mbstate_t _mbstate; } FILE; extern FILE *__stdinp; extern FILE *__stdoutp; extern FILE *__stderrp; # 228 "/usr/include/stdio.h" 3 4 void clearerr(FILE *); int fclose(FILE *); int feof(FILE *); int ferror(FILE *); int fflush(FILE *); int fgetc(FILE *); int fgetpos(FILE * , fpos_t * ); char *fgets(char * , int, FILE * ); FILE *fopen(const char * , const char * ); int fprintf(FILE * , const char * , ...); int fputc(int, FILE *); int fputs(const char * , FILE * ); size_t fread(void * , size_t, size_t, FILE * ); FILE *freopen(const char * , const char * , FILE * ); int fscanf(FILE * , const char * , ...); int fseek(FILE *, long, int); int fsetpos(FILE *, const fpos_t *); long ftell(FILE *); size_t fwrite(const void * , size_t, size_t, FILE * ); int getc(FILE *); int getchar(void); char *gets(char *); void perror(const char *); int printf(const char * , ...); int putc(int, FILE *); int putchar(int); int puts(const char *); int remove(const char *); int rename(const char *, const char *); void rewind(FILE *); int scanf(const char * , ...); void setbuf(FILE * , char * ); int setvbuf(FILE * , char * , int, size_t); int sprintf(char * , const char * , ...); int sscanf(const char * , const char * , ...); FILE *tmpfile(void); char *tmpnam(char *); int ungetc(int, FILE *); int vfprintf(FILE * , const char * , __va_list); int vprintf(const char * , __va_list); int vsprintf(char * , const char * , __va_list); int snprintf(char * , size_t, const char * , ...) __attribute__((__format__ (__printf__, 3, 4))); int vfscanf(FILE * , const char * , __va_list) __attribute__((__format__ (__scanf__, 2, 0))); int vscanf(const char * , __va_list) __attribute__((__format__ (__scanf__, 1, 0))); int vsnprintf(char * , size_t, const char * , __va_list) __attribute__((__format__ (__printf__, 3, 0))); int vsscanf(const char * , const char * , __va_list) __attribute__((__format__ (__scanf__, 2, 0))); # 299 "/usr/include/stdio.h" 3 4 char *ctermid(char *); FILE *fdopen(int, const char *); int fileno(FILE *); int pclose(FILE *); FILE *popen(const char *, const char *); int ftrylockfile(FILE *); void flockfile(FILE *); void funlockfile(FILE *); int getc_unlocked(FILE *); int getchar_unlocked(void); int putc_unlocked(int, FILE *); int putchar_unlocked(int); void clearerr_unlocked(FILE *); int feof_unlocked(FILE *); int ferror_unlocked(FILE *); int fileno_unlocked(FILE *); int fseeko(FILE *, __off_t, int); __off_t ftello(FILE *); int getw(FILE *); int putw(int, FILE *); char *tempnam(const char *, const char *); ssize_t getdelim(char ** , size_t * , int, FILE * ); int renameat(int, const char *, int, const char *); int vdprintf(int, const char * , __va_list); # 393 "/usr/include/stdio.h" 3 4 int asprintf(char **, const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); char *ctermid_r(char *); void fcloseall(void); char *fgetln(FILE *, size_t *); const char *fmtcheck(const char *, const char *) __attribute__((__format_arg__ (2))); int fpurge(FILE *); void setbuffer(FILE *, char *, int); int setlinebuf(FILE *); int vasprintf(char **, const char *, __va_list) __attribute__((__format__ (__printf__, 2, 0))); extern const int sys_nerr; extern const char *const sys_errlist[]; FILE *funopen(const void *, int (*)(void *, char *, int), int (*)(void *, const char *, int), fpos_t (*)(void *, fpos_t, int), int (*)(void *)); # 428 "/usr/include/stdio.h" 3 4 int ftruncate(int, __off_t); __off_t lseek(int, __off_t, int); void *mmap(void *, size_t, int, int, int, __off_t); int truncate(const char *, __off_t); int __srget(FILE *); int __swbuf(int, FILE *); static __inline int __sputc(int _c, FILE *_p) { if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) return (*_p->_p++ = _c); else return (__swbuf(_c, _p)); } # 481 "/usr/include/stdio.h" 3 4 extern int __isthreaded; # 515 "/usr/include/stdio.h" 3 4 # 3 "a.c" 2 # 1 "/usr/include/stdlib.h" 1 3 4 # 46 "/usr/include/stdlib.h" 3 4 typedef __rune_t rune_t; # 58 "/usr/include/stdlib.h" 3 4 typedef __wchar_t wchar_t; typedef struct { int quot; int rem; } div_t; typedef struct { long quot; long rem; } ldiv_t; extern int __mb_cur_max; void abort(void) __attribute__((__noreturn__)); int abs(int) __attribute__((__const__)); int atexit(void (*)(void)); double atof(const char *); int atoi(const char *); long atol(const char *); void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); void *calloc(size_t, size_t) __attribute__((__malloc__)); div_t div(int, int) __attribute__((__const__)); void exit(int) __attribute__((__noreturn__)); void free(void *); char *getenv(const char *); long labs(long) __attribute__((__const__)); ldiv_t ldiv(long, long) __attribute__((__const__)); void *malloc(size_t) __attribute__((__malloc__)); int mblen(const char *, size_t); size_t mbstowcs(wchar_t * , const char * , size_t); int mbtowc(wchar_t * , const char * , size_t); void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); int rand(void); void *realloc(void *, size_t); void srand(unsigned); double strtod(const char * , char ** ); float strtof(const char * , char ** ); long strtol(const char * , char ** , int); long double strtold(const char * , char ** ); unsigned long strtoul(const char * , char ** , int); int system(const char *); int wctomb(char *, wchar_t); size_t wcstombs(char * , const wchar_t * , size_t); # 130 "/usr/include/stdlib.h" 3 4 typedef struct { long long quot; long long rem; } lldiv_t; long long atoll(const char *); long long llabs(long long) __attribute__((__const__)); lldiv_t lldiv(long long, long long) __attribute__((__const__)); long long strtoll(const char * , char ** , int); unsigned long long strtoull(const char * , char ** , int); void _Exit(int) __attribute__((__noreturn__)); # 160 "/usr/include/stdlib.h" 3 4 int posix_memalign(void **, size_t, size_t); int rand_r(unsigned *); int setenv(const char *, const char *, int); int unsetenv(const char *); int getsubopt(char **, char *const *, char **); char *mkdtemp(char *); int mkstemp(char *); # 186 "/usr/include/stdlib.h" 3 4 long a64l(const char *); double drand48(void); double erand48(unsigned short[3]); int grantpt(int); char *initstate(unsigned long , char *, long); long jrand48(unsigned short[3]); char *l64a(long); void lcong48(unsigned short[7]); long lrand48(void); char *mktemp(char *); long mrand48(void); long nrand48(unsigned short[3]); int posix_openpt(int); char *ptsname(int); int putenv(char *); long random(void); char *realpath(const char *, char resolved_path[]); unsigned short *seed48(unsigned short[3]); int setkey(const char *); char *setstate( char *); void srand48(long); void srandom(unsigned long); int unlockpt(int); extern const char *_malloc_options; extern void (*_malloc_message)(const char *, const char *, const char *, const char *); # 242 "/usr/include/stdlib.h" 3 4 void abort2(const char *, int, void **) __attribute__((__noreturn__)); __uint32_t arc4random(void); void arc4random_addrandom(unsigned char *, int); void arc4random_buf(void *, size_t); void arc4random_stir(void); __uint32_t arc4random_uniform(__uint32_t); char *getbsize(int *, long *); char *cgetcap(char *, const char *, int); int cgetclose(void); int cgetent(char **, char **, const char *); int cgetfirst(char **, char **); int cgetmatch(const char *, const char *); int cgetnext(char **, char **); int cgetnum(char *, const char *, long *); int cgetset(const char *); int cgetstr(char *, const char *, char **); int cgetustr(char *, const char *, char **); int daemon(int, int); char *devname(__dev_t, __mode_t); char *devname_r(__dev_t, __mode_t, char *, int); char *fdevname(int); char *fdevname_r(int, char *, int); int getloadavg(double [], int); const char * getprogname(void); int heapsort(void *, size_t, size_t, int (*)(const void *, const void *)); int l64a_r(long, char *, int); int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); void qsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *)); int radixsort(const unsigned char **, int, const unsigned char *, unsigned); void *reallocf(void *, size_t); int rpmatch(const char *); void setprogname(const char *); int sradixsort(const unsigned char **, int, const unsigned char *, unsigned); void sranddev(void); void srandomdev(void); long long strtonum(const char *, long long, long long, const char **); __int64_t strtoq(const char *, char **, int); __uint64_t strtouq(const char *, char **, int); extern char *suboptarg; # 4 "a.c" 2 int main (int argc, char *argv[]) { (void) printf ("%s\n", "hello"); exit (0); }
cc1 コマンドによる処理
cpp コマンドで処理された結果を、今度は、cc1 コマンドで処理する。
cc1 コマンドにより、C のソースファイルは、アセンブリ言語に変換される。
/usr/libexec/cc1 a.i
__sputc main Execution times (seconds) preprocessing : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.01 (25%) wall 15 kB ( 1%) ggc lexical analysis : 0.00 ( 0%) usr 0.01 (25%) sys 0.02 (50%) wall 0 kB ( 0%) ggc parser : 0.00 ( 0%) usr 0.02 (50%) sys 0.00 ( 0%) wall 175 kB (17%) ggc global alloc : 0.00 ( 0%) usr 0.01 (25%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc TOTAL : 0.00 0.03 0.03 1061 kB
これにより、a.i から cc1 によって a.s が作成される。
.file "a.i" .section .rodata .LC0: .string "hello" .text .p2align 4,,15 .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, (%esp) call exit .size main, .-main .ident "GCC: (GNU) 4.2.1 20070719 [FreeBSD]"
as コマンドによる処理
as コマンドで、アセンブリ言語で技術された a.s をマシン語に置き換えます。
as a.s -o a.o
% file a.o a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (FreeBSD), not stripped % nm a.o U exit 00000000 T main U puts
ld コマンドによる処理
a.o は、実行可能なオブジェクトではないため、
ld コマンドによって、リンクします。
ただ、ld に a.o だけ渡しても、うまくいきません。
%ld a.o ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080 a.o(.text+0x19): In function `main': : undefined reference to `puts' a.o(.text+0x25): In function `main': : undefined reference to `exit'
libc を指定しないと puts や exit が使えませんよね。
% ld a.o -L/usr/lib -lc ld: warning: cannot find entry symbol _start; defaulting to 00000000080481e0 /usr/lib/libc.so: undefined reference to `environ' /usr/lib/libc.so: undefined reference to `__progname'
environ や __progname がないと言われます。
C プログラムの最初のエントリーポイント、 _start も定義していないので、当然ありません。
main() からはじまると思ってるかもしれませんが、main は、_start から呼ばれるのです。
C プログラムは、 C のスタートアップルーチンから起動されます。
そのため、その crt を一緒に link しなければなりません。
a.o は、こんなにたくさんのオブジェクト達とリンクされます。
ld \ -lc \ /usr/lib/crt1.o \ /usr/lib/crtbegin.o \ /usr/lib/crtend.o \ /usr/lib/crtendS.o \ /usr/lib/crti.o \ /usr/lib/crtn.o \ /tmp/a.o \ -o /tmp/a.out
これで、ようやく、実行可能な ELF ファイルができました。
% file /tmp/a.out /tmp/a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), not stripped
やっとできた a.out
さて、 a.out を実行してみます。
% /tmp/a.out hello
cc/gcc コマンドを叩くと何が起きているのか、少しだけ、理解が深まったのではないでしょうか。
gcc コマンドだけで、できるので、ほとんどの場合、手動で上記のコマンド達を叩くことはないと思います。
gcc a.c
gcc コマンド、便利ですね!
スポンサーリンク
スポンサーリンク
いつもシェア、ありがとうございます!
もっと情報を探しませんか?
関連記事
最近の記事
- パナソニック ジェットウォッシャードルツ EW-DJ61-Wのホースの修理
- LinuxセキュリティモジュールIntegrity Policy Enforcement
- アマゾンのEcho Show 5を買ったのでレビューします
- アマゾンのサイバーマンデーはAlexa Echo Show 5が安い
- Android スマートフォン OnePlus 7T と OnePlus 7の違い
- Android スマートフォン OnePlus 7 をAndroid10にアップデートしてみた
- クレジットカードのバーチャルカードの比較のまとめ
- 活動量計 Xiaomi Mi Band 4を買ってみたのでレビュー
- Android スマートフォン OnePlus 7 のレビュー
- AliExpressでスマートフォンを買い物してみた
- パソコンのホコリ対策 レンジフードフィルターと養生テープ
- 80PLUS GOLDのPC電源ユニットAntec NeoEco 750 Goldのレビュー
- イギリスの付加価値税 VAT は払い戻しを受けられる
- イギリスのロンドンでスーツケースなど荷物を預けられる場所は
- イギリスのロンドンで地下鉄やバスに乗るならオイスターカードを使おう
- イギリスのヒースロー空港からロンドン市内への行き方
- 航空便でほかの航空会社に乗り継ぎがある場合のオンラインチェックイン
- SFC会員がANA便ではなくベトナム航空のコードシェアを試して解ったこと
- ベトナムの入国審査でeチケットの掲示が必要だった話
- シアトルの交通ICカードはオルカカード(Orca)です
人気のページ
- Windows7 IME 辞書ツールで単語の登録に失敗しました
- C言語 popen()でコマンドを実行して出力を読み込む
- Windows7で休止状態にする方法
- CentOS MySQLの起動、停止、再起動
- loggerコマンドでsyslogにエラーを出力する方法
- パソコンパーツの買取をしてくれる店のまとめ
- Java Mapの使い方 get(),put(),remove(),size(),clear()
- 楽天のRポイントカードを作ってみた
- iPhone 5 から iPhone 6 に乗り換えたのでレビュー
- netstatコマンドのステータスの意味
スポンサーリンク
過去ログ
2020 : 01 02 03 04 05 06 07 08 09 10 11 122019 : 01 02 03 04 05 06 07 08 09 10 11 12
2018 : 01 02 03 04 05 06 07 08 09 10 11 12
2017 : 01 02 03 04 05 06 07 08 09 10 11 12
2016 : 01 02 03 04 05 06 07 08 09 10 11 12
2015 : 01 02 03 04 05 06 07 08 09 10 11 12
2014 : 01 02 03 04 05 06 07 08 09 10 11 12
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12