标点符(钱魏 Way)

从C语言的Hello World说起

C语言基本上大学都教过,但是很多人应该和我一样学习的时候还使用的是Windows平台,对于其中要用到的编译等知识都不了解。今天就针对这种情况来重新学习一遍C语言。

以上代码应该是最简单的C语言程序了,将上面的内容报错为hello.c,并通过gcc去编译它,具体使用到的指令为:

$ gcc -g -Wall hello.c -o hello

该命令将文件‘hello.c’中的代码编译为机器码并存储在可执行文件 ‘hello’中。机器码的文件名是通过 -o 选项指定的。该选项通常作为命令行中的最后一个参数。如果被省略,输出文件默认为 ‘a.out’。如果当前目录中与可执行文件重名的文件已经存在,它将被覆盖。

选项 -Wall 开启编译器几乎所有常用的警告。编译器有很多其他的警告选项,但 -Wall 是最常用的。默认情况下GCC 不会产生任何警告信息。当编写 C 或 C++ 程序时编译器警告非常有助于检测程序存在的问题。 注意如果有用到math.h库等非gcc默认调用的标准库,请使用-lm参数。

选项 “”-g”” 表示在生成的目标文件中带调试信息,调试信息可以在程序异常中止产生core后,帮助分析错误产生的源头,包括产生错误的文件名和行号等非常多有用的信息。

执行万上述指令后我们发现有报错,具体内容为:

hello.c:2:1: 警告: 返回类型默认为‘int’ [-Wreturn-type]
hello.c: 在函数‘main’中:
hello.c:5:1: 警告: 在有返回值的函数中,控制流程到达函数尾 [-Wreturn-type]

解决上诉问题的方法非常的简单,只要将代码修改为:

不管采用上诉的哪种代码,在命令行直接执行编译出来的hello文件,即可看到输出的hello world。下面就来细讲整个编译的过程。

compilation

上图是一个hello的c程序由gcc编译器从源码文件hello.c中读取内容并将其翻译成为一个可执行的对象文件hello的过程。这个过程包含了几个阶段:

1、预处理过程:预处理(cpp)根据以字符#开头的命令,修改原始的C程序。比如hello.c中的第一行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,插入到程序文本中。结果就得到里另一个C程序,通常是以*.i作为文件扩展名。

可通过执行如下指令获得:gcc -E hello.c -o hello.i

用记事本打开,可查看到如下的内容:

# 1 “hello.c”
# 1 “<built-in>”
# 1 “<命令行>”
# 1 “hello.c”
# 1 “/usr/include/stdio.h” 1 3 4
# 28 “/usr/include/stdio.h” 3 4
# 1 “/usr/include/features.h” 1 3 4
# 324 “/usr/include/features.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/bits/predefs.h” 1 3 4
# 325 “/usr/include/features.h” 2 3 4
# 357 “/usr/include/features.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 1 3 4
# 378 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.h” 1 3 4
# 379 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 2 3 4
# 358 “/usr/include/features.h” 2 3 4
# 389 “/usr/include/features.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 1 3 4

 

# 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.h” 1 3 4
# 5 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 2 3 4
# 1 “/usr/include/x86_64-linux-gnu/gnu/stubs-64.h” 1 3 4
# 10 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 2 3 4
# 390 “/usr/include/features.h” 2 3 4
# 29 “/usr/include/stdio.h” 2 3 4

 

 

# 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 1 3 4
# 212 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 3 4
typedef long unsigned int size_t;
# 35 “/usr/include/stdio.h” 2 3 4

# 1 “/usr/include/x86_64-linux-gnu/bits/types.h” 1 3 4
# 28 “/usr/include/x86_64-linux-gnu/bits/types.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.h” 1 3 4
# 29 “/usr/include/x86_64-linux-gnu/bits/types.h” 2 3 4
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;

typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;

 

 

 

typedef long int __quad_t;
typedef unsigned long int __u_quad_t;
# 131 “/usr/include/x86_64-linux-gnu/bits/types.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/bits/typesizes.h” 1 3 4
# 132 “/usr/include/x86_64-linux-gnu/bits/types.h” 2 3 4
typedef unsigned long int __dev_t;
typedef unsigned int __uid_t;
typedef unsigned int __gid_t;
typedef unsigned long int __ino_t;
typedef unsigned long int __ino64_t;
typedef unsigned int __mode_t;
typedef unsigned long int __nlink_t;
typedef long int __off_t;
typedef long int __off64_t;
typedef int __pid_t;
typedef struct { int __val[2]; } __fsid_t;
typedef long int __clock_t;
typedef unsigned long int __rlim_t;
typedef unsigned long int __rlim64_t;
typedef unsigned int __id_t;
typedef long int __time_t;
typedef unsigned int __useconds_t;
typedef long int __suseconds_t;

typedef int __daddr_t;
typedef long int __swblk_t;
typedef int __key_t;
typedef int __clockid_t;
typedef void * __timer_t;
typedef long int __blksize_t;
typedef long int __blkcnt_t;
typedef long int __blkcnt64_t;
typedef unsigned long int __fsblkcnt_t;
typedef unsigned long int __fsblkcnt64_t;
typedef unsigned long int __fsfilcnt_t;
typedef unsigned long int __fsfilcnt64_t;

typedef long int __ssize_t;

 

typedef __off64_t __loff_t;
typedef __quad_t *__qaddr_t;
typedef char *__caddr_t;
typedef long int __intptr_t;
typedef unsigned int __socklen_t;
# 37 “/usr/include/stdio.h” 2 3 4
# 45 “/usr/include/stdio.h” 3 4
struct _IO_FILE;

 

typedef struct _IO_FILE FILE;

 

 

# 65 “/usr/include/stdio.h” 3 4
typedef struct _IO_FILE __FILE;
# 75 “/usr/include/stdio.h” 3 4
# 1 “/usr/include/libio.h” 1 3 4
# 32 “/usr/include/libio.h” 3 4
# 1 “/usr/include/_G_config.h” 1 3 4
# 15 “/usr/include/_G_config.h” 3 4
# 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 1 3 4
# 16 “/usr/include/_G_config.h” 2 3 4
# 1 “/usr/include/wchar.h” 1 3 4
# 83 “/usr/include/wchar.h” 3 4
typedef struct
{
int __count;
union
{

unsigned int __wch;

 

char __wchb[4];
} __value;
} __mbstate_t;
# 21 “/usr/include/_G_config.h” 2 3 4

typedef struct
{
__off_t __pos;
__mbstate_t __state;
} _G_fpos_t;
typedef struct
{
__off64_t __pos;
__mbstate_t __state;
} _G_fpos64_t;
# 53 “/usr/include/_G_config.h” 3 4
typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));
typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));
typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));
typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));
# 33 “/usr/include/libio.h” 2 3 4
# 53 “/usr/include/libio.h” 3 4
# 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h” 1 3 4
# 40 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h” 3 4
typedef __builtin_va_list __gnuc_va_list;
# 54 “/usr/include/libio.h” 2 3 4
# 172 “/usr/include/libio.h” 3 4
struct _IO_jump_t; struct _IO_FILE;
# 182 “/usr/include/libio.h” 3 4
typedef void _IO_lock_t;

 

 

struct _IO_marker {
struct _IO_marker *_next;
struct _IO_FILE *_sbuf;

 

int _pos;
# 205 “/usr/include/libio.h” 3 4
};
enum __codecvt_result
{
__codecvt_ok,
__codecvt_partial,
__codecvt_error,
__codecvt_noconv
};
# 273 “/usr/include/libio.h” 3 4
struct _IO_FILE {
int _flags;
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_buf_base;
char* _IO_buf_end;

char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;

struct _IO_marker *_markers;

struct _IO_FILE *_chain;

int _fileno;

 

int _flags2;

__off_t _old_offset;

 

unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];

 

_IO_lock_t *_lock;
# 321 “/usr/include/libio.h” 3 4
__off64_t _offset;
# 330 “/usr/include/libio.h” 3 4
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;

int _mode;

char _unused2[15 * sizeof (int) – 4 * sizeof (void *) – sizeof (size_t)];

};
typedef struct _IO_FILE _IO_FILE;
struct _IO_FILE_plus;

extern struct _IO_FILE_plus _IO_2_1_stdin_;
extern struct _IO_FILE_plus _IO_2_1_stdout_;
extern struct _IO_FILE_plus _IO_2_1_stderr_;
# 366 “/usr/include/libio.h” 3 4
typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);

 

 

 

typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf,
size_t __n);

 

 

 

typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);
typedef int __io_close_fn (void *__cookie);
# 418 “/usr/include/libio.h” 3 4
extern int __underflow (_IO_FILE *);
extern int __uflow (_IO_FILE *);
extern int __overflow (_IO_FILE *, int);
# 462 “/usr/include/libio.h” 3 4
extern int _IO_getc (_IO_FILE *__fp);
extern int _IO_putc (int __c, _IO_FILE *__fp);
extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));
extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));

extern int _IO_peekc_locked (_IO_FILE *__fp);

 

 

extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
# 492 “/usr/include/libio.h” 3 4
extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
__gnuc_va_list, int *__restrict);
extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
__gnuc_va_list);
extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);
extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);

extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);
extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);

extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));
# 76 “/usr/include/stdio.h” 2 3 4
typedef __gnuc_va_list va_list;
# 91 “/usr/include/stdio.h” 3 4
typedef __off_t off_t;
# 103 “/usr/include/stdio.h” 3 4
typedef __ssize_t ssize_t;

 

 

 

typedef _G_fpos_t fpos_t;
# 165 “/usr/include/stdio.h” 3 4
# 1 “/usr/include/x86_64-linux-gnu/bits/stdio_lim.h” 1 3 4
# 166 “/usr/include/stdio.h” 2 3 4

 

extern struct _IO_FILE *stdin;
extern struct _IO_FILE *stdout;
extern struct _IO_FILE *stderr;

 

 

 

extern int remove (__const char *__filename) __attribute__ ((__nothrow__ , __leaf__));

extern int rename (__const char *__old, __const char *__new) __attribute__ ((__nothrow__ , __leaf__));
extern int renameat (int __oldfd, __const char *__old, int __newfd,
__const char *__new) __attribute__ ((__nothrow__ , __leaf__));
extern FILE *tmpfile (void) ;
# 210 “/usr/include/stdio.h” 3 4
extern char *tmpnam (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;

 

 

extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
# 228 “/usr/include/stdio.h” 3 4
extern char *tempnam (__const char *__dir, __const char *__pfx)
__attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ;
extern int fclose (FILE *__stream);
extern int fflush (FILE *__stream);

# 253 “/usr/include/stdio.h” 3 4
extern int fflush_unlocked (FILE *__stream);
# 267 “/usr/include/stdio.h” 3 4
extern FILE *fopen (__const char *__restrict __filename,
__const char *__restrict __modes) ;
extern FILE *freopen (__const char *__restrict __filename,
__const char *__restrict __modes,
FILE *__restrict __stream) ;
# 296 “/usr/include/stdio.h” 3 4

# 307 “/usr/include/stdio.h” 3 4
extern FILE *fdopen (int __fd, __const char *__modes) __attribute__ ((__nothrow__ , __leaf__)) ;
# 320 “/usr/include/stdio.h” 3 4
extern FILE *fmemopen (void *__s, size_t __len, __const char *__modes)
__attribute__ ((__nothrow__ , __leaf__)) ;
extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__ , __leaf__));

 

extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
int __modes, size_t __n) __attribute__ ((__nothrow__ , __leaf__));

 

 

extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
size_t __size) __attribute__ ((__nothrow__ , __leaf__));
extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
extern int fprintf (FILE *__restrict __stream,
__const char *__restrict __format, …);
extern int printf (__const char *__restrict __format, …);

extern int sprintf (char *__restrict __s,
__const char *__restrict __format, …) __attribute__ ((__nothrow__));

 

 

extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format,
__gnuc_va_list __arg);
extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg);

extern int vsprintf (char *__restrict __s, __const char *__restrict __format,
__gnuc_va_list __arg) __attribute__ ((__nothrow__));

 

 

extern int snprintf (char *__restrict __s, size_t __maxlen,
__const char *__restrict __format, …)
__attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 4)));

extern int vsnprintf (char *__restrict __s, size_t __maxlen,
__const char *__restrict __format, __gnuc_va_list __arg)
__attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 0)));

# 418 “/usr/include/stdio.h” 3 4
extern int vdprintf (int __fd, __const char *__restrict __fmt,
__gnuc_va_list __arg)
__attribute__ ((__format__ (__printf__, 2, 0)));
extern int dprintf (int __fd, __const char *__restrict __fmt, …)
__attribute__ ((__format__ (__printf__, 2, 3)));
extern int fscanf (FILE *__restrict __stream,
__const char *__restrict __format, …) ;
extern int scanf (__const char *__restrict __format, …) ;

extern int sscanf (__const char *__restrict __s,
__const char *__restrict __format, …) __attribute__ ((__nothrow__ , __leaf__));
# 449 “/usr/include/stdio.h” 3 4
extern int fscanf (FILE *__restrict __stream, __const char *__restrict __format, …) __asm__ (“” “__isoc99_fscanf”)

;
extern int scanf (__const char *__restrict __format, …) __asm__ (“” “__isoc99_scanf”)
;
extern int sscanf (__const char *__restrict __s, __const char *__restrict __format, …) __asm__ (“” “__isoc99_sscanf”) __attribute__ ((__nothrow__ , __leaf__))

;
# 469 “/usr/include/stdio.h” 3 4
extern int vfscanf (FILE *__restrict __s, __const char *__restrict __format,
__gnuc_va_list __arg)
__attribute__ ((__format__ (__scanf__, 2, 0))) ;

 

 

extern int vscanf (__const char *__restrict __format, __gnuc_va_list __arg)
__attribute__ ((__format__ (__scanf__, 1, 0))) ;
extern int vsscanf (__const char *__restrict __s,
__const char *__restrict __format, __gnuc_va_list __arg)
__attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
# 500 “/usr/include/stdio.h” 3 4
extern int vfscanf (FILE *__restrict __s, __const char *__restrict __format, __gnuc_va_list __arg) __asm__ (“” “__isoc99_vfscanf”)

 

__attribute__ ((__format__ (__scanf__, 2, 0))) ;
extern int vscanf (__const char *__restrict __format, __gnuc_va_list __arg) __asm__ (“” “__isoc99_vscanf”)

__attribute__ ((__format__ (__scanf__, 1, 0))) ;
extern int vsscanf (__const char *__restrict __s, __const char *__restrict __format, __gnuc_va_list __arg) __asm__ (“” “__isoc99_vsscanf”) __attribute__ ((__nothrow__ , __leaf__))

 

__attribute__ ((__format__ (__scanf__, 2, 0)));
# 528 “/usr/include/stdio.h” 3 4

 

 

 

 

extern int fgetc (FILE *__stream);
extern int getc (FILE *__stream);

 

 

extern int getchar (void);

# 556 “/usr/include/stdio.h” 3 4
extern int getc_unlocked (FILE *__stream);
extern int getchar_unlocked (void);
# 567 “/usr/include/stdio.h” 3 4
extern int fgetc_unlocked (FILE *__stream);

 

 

 

 

 

extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream);

 

 

extern int putchar (int __c);

# 600 “/usr/include/stdio.h” 3 4
extern int fputc_unlocked (int __c, FILE *__stream);

 

 

 

extern int putc_unlocked (int __c, FILE *__stream);
extern int putchar_unlocked (int __c);
extern int getw (FILE *__stream);
extern int putw (int __w, FILE *__stream);
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
;
extern char *gets (char *__s) ;

# 662 “/usr/include/stdio.h” 3 4
extern __ssize_t __getdelim (char **__restrict __lineptr,
size_t *__restrict __n, int __delimiter,
FILE *__restrict __stream) ;
extern __ssize_t getdelim (char **__restrict __lineptr,
size_t *__restrict __n, int __delimiter,
FILE *__restrict __stream) ;

 

 

 

extern __ssize_t getline (char **__restrict __lineptr,
size_t *__restrict __n,
FILE *__restrict __stream) ;
extern int fputs (__const char *__restrict __s, FILE *__restrict __stream);

 

 

extern int puts (__const char *__s);
extern int ungetc (int __c, FILE *__stream);
extern size_t fread (void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream) ;
extern size_t fwrite (__const void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __s);

# 734 “/usr/include/stdio.h” 3 4
extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream) ;
extern size_t fwrite_unlocked (__const void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream);
extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream) ;
extern void rewind (FILE *__stream);

# 770 “/usr/include/stdio.h” 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence);
extern __off_t ftello (FILE *__stream) ;
# 789 “/usr/include/stdio.h” 3 4
extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
extern int fsetpos (FILE *__stream, __const fpos_t *__pos);
# 812 “/usr/include/stdio.h” 3 4

# 821 “/usr/include/stdio.h” 3 4
extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));

extern int feof (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;

extern int ferror (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void perror (__const char *__s);
# 1 “/usr/include/x86_64-linux-gnu/bits/sys_errlist.h” 1 3 4
# 27 “/usr/include/x86_64-linux-gnu/bits/sys_errlist.h” 3 4
extern int sys_nerr;
extern __const char *__const sys_errlist[];
# 851 “/usr/include/stdio.h” 2 3 4
extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
# 870 “/usr/include/stdio.h” 3 4
extern FILE *popen (__const char *__command, __const char *__modes) ;

 

 

extern int pclose (FILE *__stream);

 

 

extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
# 910 “/usr/include/stdio.h” 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));

 

extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 940 “/usr/include/stdio.h” 3 4

# 2 “hello.c” 2
int main()
{
printf(“hello world\n”);
return 0;
}

以上部分代码可以看出除了#include <stdio.h>指令之外其他指令并未被改变。

2、编译阶段:编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文件格式确切地描述了一条低级机器语言指令。

可通过如下指令获得:gcc -S hello.c -o 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
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident “GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3″
.section .note.GNU-stack,””,@progbits

3、汇编阶段:汇编器将hello.s翻译成机器语言指令,把这些指令打包成一种可重定位目标程序的格式,并把结果保存在hello.o中,hello.o是一个二进制文件,它的字节编码是机器语言指令,而不是字符。

可通过如下指令获得:gcc -c hello.c,最终生成的hello.o文件需要使用objdump打开,具体指令为:objdump -d hello.o

获取的内容为:

hello.o: file format elf64-x86-64
Disassembly of section .text:

0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: bf 00 00 00 00 mov $0x0,%edi
9: e8 00 00 00 00 callq e <main+0xe>
e: b8 00 00 00 00 mov $0x0,%eax
13: 5d pop %rbp
14: c3 retq

4.、链接阶段:hello.c程序中调用了printf函数,而printf函数存在于一个名为printf.o的单独的预编译好的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器就负责处理这种合并,结果就得到hello文件,它是一个可执行文件,可以被加载到内存中由系统执行。

使用的指令为:gcc hello.o -o hello,最终生成了一个hello文件,同样此hello文件可用通过objdump打开:objdump -d hello

打开后的内容为:

hello: file format elf64-x86-64
Disassembly of section .init:

00000000004003c8 <_init>:
4003c8: 48 83 ec 08 sub $0x8,%rsp
4003cc: e8 6b 00 00 00 callq 40043c <call_gmon_start>
4003d1: e8 fa 00 00 00 callq 4004d0 <frame_dummy>
4003d6: e8 d5 01 00 00 callq 4005b0 <__do_global_ctors_aux>
4003db: 48 83 c4 08 add $0x8,%rsp
4003df: c3 retq

Disassembly of section .plt:

00000000004003e0 <puts@plt-0x10>:
4003e0: ff 35 0a 0c 20 00 pushq 0x200c0a(%rip) # 600ff0 <_GLOBAL_OFFSET_TABLE_+0x8>
4003e6: ff 25 0c 0c 20 00 jmpq *0x200c0c(%rip) # 600ff8 <_GLOBAL_OFFSET_TABLE_+0x10>
4003ec: 0f 1f 40 00 nopl 0x0(%rax)

00000000004003f0 <puts@plt>:
4003f0: ff 25 0a 0c 20 00 jmpq *0x200c0a(%rip) # 601000 <_GLOBAL_OFFSET_TABLE_+0x18>
4003f6: 68 00 00 00 00 pushq $0x0
4003fb: e9 e0 ff ff ff jmpq 4003e0 <_init+0x18>

0000000000400400 <__libc_start_main@plt>:
400400: ff 25 02 0c 20 00 jmpq *0x200c02(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x20>
400406: 68 01 00 00 00 pushq $0x1
40040b: e9 d0 ff ff ff jmpq 4003e0 <_init+0x18>

Disassembly of section .text:

0000000000400410 <_start>:
400410: 31 ed xor %ebp,%ebp
400412: 49 89 d1 mov %rdx,%r9
400415: 5e pop %rsi
400416: 48 89 e2 mov %rsp,%rdx
400419: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40041d: 50 push %rax
40041e: 54 push %rsp
40041f: 49 c7 c0 a0 05 40 00 mov $0x4005a0,%r8
400426: 48 c7 c1 10 05 40 00 mov $0x400510,%rcx
40042d: 48 c7 c7 f4 04 40 00 mov $0x4004f4,%rdi
400434: e8 c7 ff ff ff callq 400400 <__libc_start_main@plt>
400439: f4 hlt
40043a: 90 nop
40043b: 90 nop

000000000040043c <call_gmon_start>:
40043c: 48 83 ec 08 sub $0x8,%rsp
400440: 48 8b 05 99 0b 20 00 mov 0x200b99(%rip),%rax # 600fe0 <_DYNAMIC+0x190>
400447: 48 85 c0 test %rax,%rax
40044a: 74 02 je 40044e <call_gmon_start+0x12>
40044c: ff d0 callq *%rax
40044e: 48 83 c4 08 add $0x8,%rsp
400452: c3 retq
400453: 90 nop
400454: 90 nop
400455: 90 nop
400456: 90 nop
400457: 90 nop
400458: 90 nop
400459: 90 nop
40045a: 90 nop
40045b: 90 nop
40045c: 90 nop
40045d: 90 nop
40045e: 90 nop
40045f: 90 nop

0000000000400460 <__do_global_dtors_aux>:
400460: 55 push %rbp
400461: 48 89 e5 mov %rsp,%rbp
400464: 53 push %rbx
400465: 48 83 ec 08 sub $0x8,%rsp
400469: 80 3d b0 0b 20 00 00 cmpb $0x0,0x200bb0(%rip) # 601020 <__bss_start>
400470: 75 4b jne 4004bd <__do_global_dtors_aux+0x5d>
400472: bb 40 0e 60 00 mov $0x600e40,%ebx
400477: 48 8b 05 aa 0b 20 00 mov 0x200baa(%rip),%rax # 601028 <dtor_idx.6533>
40047e: 48 81 eb 38 0e 60 00 sub $0x600e38,%rbx
400485: 48 c1 fb 03 sar $0x3,%rbx
400489: 48 83 eb 01 sub $0x1,%rbx
40048d: 48 39 d8 cmp %rbx,%rax
400490: 73 24 jae 4004b6 <__do_global_dtors_aux+0x56>
400492: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
400498: 48 83 c0 01 add $0x1,%rax
40049c: 48 89 05 85 0b 20 00 mov %rax,0x200b85(%rip) # 601028 <dtor_idx.6533>
4004a3: ff 14 c5 38 0e 60 00 callq *0x600e38(,%rax,8)
4004aa: 48 8b 05 77 0b 20 00 mov 0x200b77(%rip),%rax # 601028 <dtor_idx.6533>
4004b1: 48 39 d8 cmp %rbx,%rax
4004b4: 72 e2 jb 400498 <__do_global_dtors_aux+0x38>
4004b6: c6 05 63 0b 20 00 01 movb $0x1,0x200b63(%rip) # 601020 <__bss_start>
4004bd: 48 83 c4 08 add $0x8,%rsp
4004c1: 5b pop %rbx
4004c2: 5d pop %rbp
4004c3: c3 retq
4004c4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4004cb: 00 00 00 00 00

00000000004004d0 <frame_dummy>:
4004d0: 48 83 3d 70 09 20 00 cmpq $0x0,0x200970(%rip) # 600e48 <__JCR_END__>
4004d7: 00
4004d8: 55 push %rbp
4004d9: 48 89 e5 mov %rsp,%rbp
4004dc: 74 12 je 4004f0 <frame_dummy+0x20>
4004de: b8 00 00 00 00 mov $0x0,%eax
4004e3: 48 85 c0 test %rax,%rax
4004e6: 74 08 je 4004f0 <frame_dummy+0x20>
4004e8: 5d pop %rbp
4004e9: bf 48 0e 60 00 mov $0x600e48,%edi
4004ee: ff e0 jmpq *%rax
4004f0: 5d pop %rbp
4004f1: c3 retq
4004f2: 90 nop
4004f3: 90 nop

00000000004004f4 <main>:
4004f4: 55 push %rbp
4004f5: 48 89 e5 mov %rsp,%rbp
4004f8: bf fc 05 40 00 mov $0x4005fc,%edi
4004fd: e8 ee fe ff ff callq 4003f0 <puts@plt>
400502: b8 00 00 00 00 mov $0x0,%eax
400507: 5d pop %rbp
400508: c3 retq
400509: 90 nop
40050a: 90 nop
40050b: 90 nop
40050c: 90 nop
40050d: 90 nop
40050e: 90 nop
40050f: 90 nop

0000000000400510 <__libc_csu_init>:
400510: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp)
400515: 4c 89 64 24 e0 mov %r12,-0x20(%rsp)
40051a: 48 8d 2d 03 09 20 00 lea 0x200903(%rip),%rbp # 600e24 <__init_array_end>
400521: 4c 8d 25 fc 08 20 00 lea 0x2008fc(%rip),%r12 # 600e24 <__init_array_end>
400528: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp)
40052d: 4c 89 74 24 f0 mov %r14,-0x10(%rsp)
400532: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp)
400537: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp)
40053c: 48 83 ec 38 sub $0x38,%rsp
400540: 4c 29 e5 sub %r12,%rbp
400543: 41 89 fd mov %edi,%r13d
400546: 49 89 f6 mov %rsi,%r14
400549: 48 c1 fd 03 sar $0x3,%rbp
40054d: 49 89 d7 mov %rdx,%r15
400550: e8 73 fe ff ff callq 4003c8 <_init>
400555: 48 85 ed test %rbp,%rbp
400558: 74 1c je 400576 <__libc_csu_init+0x66>
40055a: 31 db xor %ebx,%ebx
40055c: 0f 1f 40 00 nopl 0x0(%rax)
400560: 4c 89 fa mov %r15,%rdx
400563: 4c 89 f6 mov %r14,%rsi
400566: 44 89 ef mov %r13d,%edi
400569: 41 ff 14 dc callq *(%r12,%rbx,8)
40056d: 48 83 c3 01 add $0x1,%rbx
400571: 48 39 eb cmp %rbp,%rbx
400574: 75 ea jne 400560 <__libc_csu_init+0x50>
400576: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx
40057b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400580: 4c 8b 64 24 18 mov 0x18(%rsp),%r12
400585: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13
40058a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14
40058f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15
400594: 48 83 c4 38 add $0x38,%rsp
400598: c3 retq
400599: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

00000000004005a0 <__libc_csu_fini>:
4005a0: f3 c3 repz retq
4005a2: 90 nop
4005a3: 90 nop
4005a4: 90 nop
4005a5: 90 nop
4005a6: 90 nop
4005a7: 90 nop
4005a8: 90 nop
4005a9: 90 nop
4005aa: 90 nop
4005ab: 90 nop
4005ac: 90 nop
4005ad: 90 nop
4005ae: 90 nop
4005af: 90 nop

00000000004005b0 <__do_global_ctors_aux>:
4005b0: 55 push %rbp
4005b1: 48 89 e5 mov %rsp,%rbp
4005b4: 53 push %rbx
4005b5: 48 83 ec 08 sub $0x8,%rsp
4005b9: 48 8b 05 68 08 20 00 mov 0x200868(%rip),%rax # 600e28 <__CTOR_LIST__>
4005c0: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
4005c4: 74 19 je 4005df <__do_global_ctors_aux+0x2f>
4005c6: bb 28 0e 60 00 mov $0x600e28,%ebx
4005cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4005d0: 48 83 eb 08 sub $0x8,%rbx
4005d4: ff d0 callq *%rax
4005d6: 48 8b 03 mov (%rbx),%rax
4005d9: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
4005dd: 75 f1 jne 4005d0 <__do_global_ctors_aux+0x20>
4005df: 48 83 c4 08 add $0x8,%rsp
4005e3: 5b pop %rbx
4005e4: 5d pop %rbp
4005e5: c3 retq
4005e6: 90 nop
4005e7: 90 nop

Disassembly of section .fini:

00000000004005e8 <_fini>:
4005e8: 48 83 ec 08 sub $0x8,%rsp
4005ec: e8 6f fe ff ff callq 400460 <__do_global_dtors_aux>
4005f1: 48 83 c4 08 add $0x8,%rsp
4005f5: c3 retq

经过上面四个过程,我们就可以把一个源代码文件编译成机器能运行的可执行文件。这个可执行文件刚开始是保存在磁盘上,当计算机要运行这个程序的时候,hello就被加载到内存中,接着程序指令被不断复制到寄存器中由CPU来执行,最后把”hello world”从寄存器中打到显示设备上。这就是hello程序整个执行过程。

大致的过程就这么多,关于中间涉及到的其他内容由于篇幅的限制,下篇文章再详述~尽请期待~

码字很辛苦,转载请注明来自标点符《从C语言的Hello World说起》

评论