スポンサーリンク

このドキュメントの内容は、以下の通りです。

たまたまgccの話をすることになったので、忘れかけていたことを思い出したので、記事として残しておきます。

普段、なにげなく実行しているcc/gccコマンドさんですが、 gcc がなんでもかんでもやっているのではなく、 gcc は、他のプログラムを呼び出して、処理をしてもらっています。

Cプログラムのコンパイルの過程で、
プリプロセッサディレクティブを処理し、
アセンブリコードへ変換し、
機械語へ変換し、
オブジェクトを結合します。

gcc は、中間言語に変換していた気がするけど、
おおざっぱに言えば、gccを実行すると、その裏側では、以下のコマンドによって、こんな順番で処理される。

  • cpp
  • cc1
  • as
  • ld
cpp によって、プリプロセッサディレクティブが処理されます。
たとえば、 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 コマンド、便利ですね!



スポンサーリンク
スポンサーリンク
 
いつもシェア、ありがとうございます!


もっと情報を探しませんか?

関連記事

最近の記事

人気のページ

スポンサーリンク
 

過去ログ

2020 : 01 02 03 04 05 06 07 08 09 10 11 12
2019 : 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

サイト

Vim入門

C言語入門

C++入門

JavaScript/Node.js入門

Python入門

FreeBSD入門

Ubuntu入門

セキュリティ入門

パソコン自作入門

ブログ

トップ


プライバシーポリシー