??本文屬于嵌入式系統(tǒng)的基礎(chǔ)知識(shí),主要介紹編譯過(guò)程和交叉編譯。對(duì)于基于ARM內(nèi)核的微處理器移植操作系統(tǒng),不可避免的需要使用交叉編譯。交叉編譯指的是不同平臺(tái)間編譯程序代碼的操作,不同平臺(tái)有兩方面:(1)不同的操作系統(tǒng);(2)不同的處理器平臺(tái),如ARM和X86。
gcc編譯器的工作原理
??編譯器是具有編輯代碼并能夠?qū)⒏呒?jí)語(yǔ)言代碼翻譯為機(jī)器碼的工具例如編寫的C語(yǔ)言代碼最終為.c格式文件;java語(yǔ)言代碼最終為.java格式文件,這些高級(jí)語(yǔ)言組成的文件計(jì)算機(jī)是無(wú)法直接運(yùn)行的,就需要一個(gè)“翻譯”工具將高級(jí)語(yǔ)言轉(zhuǎn)換為計(jì)算機(jī)可以識(shí)別的機(jī)器語(yǔ)言,這個(gè)過(guò)程就是譯碼。
??譯碼主要分為四個(gè)階段:預(yù)處理,編譯,匯編,鏈接。經(jīng)過(guò)鏈接后形成的可執(zhí)行文件,然后下載到目標(biāo)OS下執(zhí)行:
預(yù)處理過(guò)程
首先,編寫一個(gè)最簡(jiǎn)單的helloworld.c文件
#include <stdio.h>
int main()
{
print("Hello, World!"); //字符串需要""包起來(lái)
return 0;
}
以gcc預(yù)處理為例,包含以下幾個(gè)操作:
- 將包含的頭文件以及宏定義的值找到并替換為最終內(nèi)容;
- 自動(dòng)刪除代碼中的注釋;
- 添加行號(hào)和標(biāo)識(shí);
- 生成.i預(yù)處理文件
gcc -E hello.c -o hello.i #預(yù)處理命令
生成hello.i文件,查看hello.i文件:
# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
# 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 424 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 427 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 428 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
# 429 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 425 "/usr/include/features.h" 2 3 4
# 448 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
# 449 "/usr/include/features.h" 2 3 4
# 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 1 3 4
# 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4
# 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4
# 27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 28 "/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;
typedef long int __intmax_t;
typedef unsigned long int __uintmax_t;
# 130 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/typesizes.h" 1 3 4
# 131 "/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 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 __fsword_t;
typedef long int __ssize_t;
typedef long int __syscall_slong_t;
typedef unsigned long int __syscall_ulong_t;
typedef __off64_t __loff_t;
typedef char *__caddr_t;
typedef long int __intptr_t;
typedef unsigned int __socklen_t;
typedef int __sig_atomic_t;
# 36 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/__FILE.h" 1 3 4
struct _IO_FILE;
typedef struct _IO_FILE __FILE;
# 37 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/FILE.h" 1 3 4
struct _IO_FILE;
typedef struct _IO_FILE FILE;
# 38 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libio.h" 1 3 4
# 35 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/_G_config.h" 1 3 4
# 19 "/usr/include/x86_64-linux-gnu/bits/_G_config.h" 3 4
# 1 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 1 3 4
# 20 "/usr/include/x86_64-linux-gnu/bits/_G_config.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 1 3 4
# 13 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 3 4
typedef struct
{
int __count;
union
{
unsigned int __wch;
char __wchb[4];
} __value;
} __mbstate_t;
# 22 "/usr/include/x86_64-linux-gnu/bits/_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;
# 36 "/usr/include/x86_64-linux-gnu/bits/libio.h" 2 3 4
# 53 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
# 1 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stdarg.h" 1 3 4
# 40 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 54 "/usr/include/x86_64-linux-gnu/bits/libio.h" 2 3 4
# 149 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
struct _IO_jump_t; struct _IO_FILE;
typedef void _IO_lock_t;
struct _IO_marker {
struct _IO_marker *_next;
struct _IO_FILE *_sbuf;
int _pos;
# 177 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
};
enum __codecvt_result
{
__codecvt_ok,
__codecvt_partial,
__codecvt_error,
__codecvt_noconv
};
# 245 "/usr/include/x86_64-linux-gnu/bits/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;
# 293 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
__off64_t _offset;
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_;
# 337 "/usr/include/x86_64-linux-gnu/bits/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);
# 389 "/usr/include/x86_64-linux-gnu/bits/libio.h" 3 4
extern int __underflow (_IO_FILE *);
extern int __uflow (_IO_FILE *);
extern int __overflow (_IO_FILE *, int);
# 433 "/usr/include/x86_64-linux-gnu/bits/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__));
# 462 "/usr/include/x86_64-linux-gnu/bits/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__));
# 42 "/usr/include/stdio.h" 2 3 4
typedef __gnuc_va_list va_list;
# 57 "/usr/include/stdio.h" 3 4
typedef __off_t off_t;
# 71 "/usr/include/stdio.h" 3 4
typedef __ssize_t ssize_t;
typedef _G_fpos_t fpos_t;
# 131 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/stdio_lim.h" 1 3 4
# 132 "/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) ;
# 173 "/usr/include/stdio.h" 3 4
extern char *tmpnam (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
# 190 "/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);
# 213 "/usr/include/stdio.h" 3 4
extern int fflush_unlocked (FILE *__stream);
# 232 "/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) ;
# 265 "/usr/include/stdio.h" 3 4
extern FILE *fdopen (int __fd, const char *__modes) __attribute__ ((__nothrow__ , __leaf__)) ;
# 278 "/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)));
# 365 "/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__));
# 395 "/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__))
;
# 420 "/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)));
# 443 "/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)));
# 477 "/usr/include/stdio.h" 3 4
extern int fgetc (FILE *__stream);
extern int getc (FILE *__stream);
extern int getchar (void);
# 495 "/usr/include/stdio.h" 3 4
extern int getc_unlocked (FILE *__stream);
extern int getchar_unlocked (void);
# 506 "/usr/include/stdio.h" 3 4
extern int fgetc_unlocked (FILE *__stream);
# 517 "/usr/include/stdio.h" 3 4
extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream);
extern int putchar (int __c);
# 537 "/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)
;
# 603 "/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);
# 673 "/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);
# 707 "/usr/include/stdio.h" 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence);
extern __off_t ftello (FILE *__stream) ;
# 731 "/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);
# 757 "/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
# 26 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 3 4
extern int sys_nerr;
extern const char *const sys_errlist[];
# 782 "/usr/include/stdio.h" 2 3 4
extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
# 800 "/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__));
# 840 "/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__));
# 868 "/usr/include/stdio.h" 3 4
# 2 "hello.c" 2
# 2 "hello.c"
int main()
{
print("Hello, World!");
return 0;
}
編譯階段
??編譯階段的作用是將預(yù)處理文件翻譯為匯編文件。對(duì)于編譯器來(lái)說(shuō),編譯階段是最復(fù)雜的處理過(guò)程,這個(gè)過(guò)程包括:
- 詞法分析;
- 語(yǔ)法分析;
- 語(yǔ)義分析與中間代碼產(chǎn)生;
- 優(yōu)化;
- 目標(biāo)代碼生成
gcc -S hello.i -o hello.s #生成匯編代碼
gcc -S hello.c -o hello.s #也可以直接將.C文件編譯為匯編文件
查看hello.s匯編文件:
.file "hello.c"
.text
.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
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits
匯編階段
編譯器的匯編過(guò)程就是as匯編器將.s匯編文件轉(zhuǎn)換成中間目標(biāo)文件。將編譯過(guò)程生成的.s匯編代碼轉(zhuǎn)換為機(jī)器碼的中間目標(biāo)文件,中間目標(biāo)文件是二進(jìn)制文件,并不能直接運(yùn)行,需要鏈接后才能運(yùn)行。
gcc -c hello.s -o hello.o
鏈接階段
??鏈接是ld鏈接器把一個(gè)或多個(gè)中間目標(biāo)文件和所需的靜態(tài)庫(kù)文件(.a)、動(dòng)態(tài)庫(kù)文件(.so)鏈接成可執(zhí)行文件。
靜態(tài)鏈接:鏈接靜態(tài)庫(kù)文件,把庫(kù)文件的代碼全部加到可執(zhí)行文件中,生成的可執(zhí)行文件較大,運(yùn)行時(shí)不需要庫(kù)文件;
動(dòng)態(tài)鏈接:鏈接時(shí)沒(méi)有把庫(kù)文件代碼加到可執(zhí)行文件中,可執(zhí)行文件運(yùn)行時(shí)有鏈接文件加載庫(kù),節(jié)省系統(tǒng)開銷,需要依賴庫(kù)文件。gcc hello.o -o hello
交叉編譯
??交叉編譯工具鏈:編譯器、連接器、解釋器,主要由binutils、gcc、glibc組成。
??編譯過(guò)程包括了預(yù)處理、編譯、匯編、鏈接等功能。每個(gè)子功能都是一個(gè)單獨(dú)的工具來(lái)實(shí)現(xiàn),它們合在一起形成了一個(gè)完整的工具集。同時(shí)編譯過(guò)程又是一個(gè)有先后順序的流程,牽涉到工具的使用順序,每個(gè)工具按照先后關(guān)系串聯(lián)在一起,形成了一個(gè)編譯工具鏈。交叉編譯工具鏈就是為了編譯跨平臺(tái)體系結(jié)構(gòu)的程序代碼而形成的由多個(gè)子工具構(gòu)成的一套完整的工具集。同時(shí),它隱藏了預(yù)處理、編譯、匯編、鏈接等細(xì)節(jié),當(dāng)我們指定了源文件(.c)時(shí),它會(huì)自動(dòng)按照編譯流程調(diào)用不同的子工具,自動(dòng)生成最終的二進(jìn)制程序映像(.bin)。
注意:嚴(yán)格意義上來(lái)說(shuō),交叉編譯器,只是指交叉編譯的gcc,但是實(shí)際上為了方便,我們常說(shuō)的交叉編譯器就是交叉編譯工具鏈
交叉編譯工具鏈命名規(guī)則
在使用交叉編譯鏈時(shí),常常會(huì)看到下面這樣的名字:
- arm-linux-gnueabihf-
- arm-none-linux-gnueabi-
- arm-cortex_a8-linux-gnueabi-
- mips-malta-linux-gnu-
??這些交叉編譯鏈的命名通常會(huì)遵循一定的規(guī)則:arch-vender-os-abi,各字段說(shuō)明如下:
arch:目標(biāo)cpu架構(gòu),比如mips、arm、x86、riscv等,該字段通常不會(huì)省略
vendor:提供此編譯工具鏈的廠商名稱或是廠商特定信息,該字段只是標(biāo)識(shí)信息,沒(méi)有實(shí)際意義,可以為none、cross、unknow或是直接省略
os:目標(biāo)設(shè)備上運(yùn)行的操作系統(tǒng),常見的有l(wèi)inux、none(裸機(jī))等
abi:應(yīng)用程序二進(jìn)制接口(Application Binary Interface),交叉編譯鏈所選擇的庫(kù)函數(shù)和目標(biāo)映像的規(guī)范,該字段常見的值有abi 、eabi(embedded abi)、gun(glibc+oabi)、gnueabi(glibc+eabi)、gnueabihf(hf 指默認(rèn)編譯參數(shù)支持硬件浮點(diǎn)功能)等。
??從授權(quán)上,分為免費(fèi)授權(quán)版和付費(fèi)授權(quán)版。
免費(fèi)版目前有三大主流工具商提供,第一是GNU(提供源碼,自行編譯制作),第二是 Codesourcery,第三是Linora。
收費(fèi)版有ARM原廠提供的armcc、IAR提供的編譯器等等,因?yàn)檫@些價(jià)格都比較昂貴,不適合學(xué)習(xí)用戶使用,所以不做講述。
arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已經(jīng)被Mentor收購(gòu))基于GCC推出的的ARM交叉編譯工具??捎糜诮徊婢幾gARM(32位)系統(tǒng)中所有環(huán)節(jié)的代碼,包括裸機(jī)程序、u-boot、Linux kernel、filesystem和App應(yīng)用程序。
arm-linux-gnueabihf-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉編譯工具。可用于交叉編譯ARM(32位)系統(tǒng)中所有環(huán)節(jié)的代碼,包括裸機(jī)程序、u-boot、Linux kernel、filesystem和App應(yīng)用程序。
aarch64-linux-gnu-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉編譯工具??捎糜诮徊婢幾gARMv8 64位目標(biāo)中的裸機(jī)程序、u-boot、Linux kernel、filesystem和App應(yīng)用程序。
arm-none-elf-gcc:是 Codesourcery 公司(目前已經(jīng)被Mentor收購(gòu))基于GCC推出的的ARM交叉編譯工具??捎糜诮徊婢幾gARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
arm-none-eabi-gcc:是 GNU 推出的的ARM交叉編譯工具??捎糜诮徊婢幾gARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
??根據(jù)對(duì)操作系統(tǒng)的支持與否,ARM GCC可分為支持和不支持操作系統(tǒng),如
arm-none-eabi:這個(gè)是沒(méi)有操作系統(tǒng)的,自然不可能支持那些跟操作系統(tǒng)關(guān)系密切的函數(shù),比如fork(2)。他使用的是newlib這個(gè)專用于嵌入式系統(tǒng)的C庫(kù)。
arm-none-linux-eabi:用于Linux的,使用Glibc
實(shí)例
1、arm-none-eabi-gcc(ARM architecture,no vendor,not target an operating system,complies with the ARM EABI)
??用于編譯 ARM 架構(gòu)的裸機(jī)系統(tǒng)(包括 ARM Linux 的 boot、kernel,不適用編譯 Linux 應(yīng)用 Application),一般適合 ARM7、Cortex-M 和 Cortex-R 內(nèi)核的芯片使用,所以不支持那些跟操作系統(tǒng)關(guān)系密切的函數(shù),比如fork(2),他使用的是 newlib 這個(gè)專用于嵌入式系統(tǒng)的C庫(kù)。
2、arm-none-linux-gnueabi-gcc(ARM architecture, no vendor, creates binaries that run on the Linux operating system, and uses the GNU EABI)
??主要用于基于ARM架構(gòu)的Linux系統(tǒng),可用于編譯 ARM 架構(gòu)的 u-boot、Linux內(nèi)核、linux應(yīng)用等。arm-none-linux-gnueabi基于GCC,使用Glibc庫(kù),經(jīng)過(guò) Codesourcery 公司優(yōu)化過(guò)推出的編譯器。arm-none-linux-gnueabi-xxx 交叉編譯工具的浮點(diǎn)運(yùn)算非常優(yōu)秀。一般ARM9、ARM11、Cortex-A 內(nèi)核,帶有 Linux 操作系統(tǒng)的會(huì)用到。
3、arm-eabi-gcc
??Android ARM 編譯器。
4、armcc
??ARM 公司推出的編譯工具,功能和 arm-none-eabi 類似,可以編譯裸機(jī)程序(u-boot、kernel),但是不能編譯 Linux 應(yīng)用程序。armcc一般和ARM開發(fā)工具一起,Keil MDK、ADS、RVDS和DS-5中的編譯器都是armcc,所以 armcc 編譯器都是收費(fèi)的。
5、arm-none-uclinuxeabi-gcc 和 arm-none-symbianelf-gcc
arm-none-uclinuxeabi 用于uCLinux,使用Glibc。
arm-none-symbianelf 用于symbian 。
Codesourcery
??Codesourcery推出的產(chǎn)品叫Sourcery G++ Lite Edition,其中基于command-line的編譯器是免費(fèi)的,在官網(wǎng)上可以下載,而其中包含的IDE和debug 工具是收費(fèi)的,當(dāng)然也有30天試用版本的,目前CodeSourcery已經(jīng)由明導(dǎo)國(guó)際(Mentor Graphics)收購(gòu),所以原本的網(wǎng)站風(fēng)格已經(jīng)全部變?yōu)?Mentor 樣式,但是 Sourcery G++ Lite Edition 同樣可以注冊(cè)后免費(fèi)下載。
??Codesourcery一直是在做ARM目標(biāo) GCC 的開發(fā)和優(yōu)化,它的ARM GCC在目前在市場(chǎng)上非常優(yōu)秀,很多 patch 可能還沒(méi)被gcc接受,所以還是應(yīng)該直接用它的(而且他提供Windows下[mingw交叉編譯的]和Linux下的二進(jìn)制版本,比較方便;如果不是很有時(shí)間和興趣,不建議下載 src 源碼包自己編譯,很麻煩,Codesourcery給的shell腳本很多時(shí)候根本沒(méi)辦法直接用,得自行提取關(guān)鍵的部分手工執(zhí)行,又費(fèi)精力又費(fèi)時(shí)間,如果想知道細(xì)節(jié),其實(shí)不用自己編譯一遍,看看他是用什么步驟構(gòu)建的即可,如果你對(duì)交叉編譯器感興趣的話。
ABI 和 EABI
- ABI:二進(jìn)制應(yīng)用程序接口(Application Binary Interface (ABI) for the ARM Architecture)。在計(jì)算機(jī)中,應(yīng)用二進(jìn)制接口描述了應(yīng)用程序(或者其他類型)和操作系統(tǒng)之間或其他應(yīng)用程序的低級(jí)接口。
- EABI:嵌入式ABI。嵌入式應(yīng)用二進(jìn)制接口指定了文件格式、數(shù)據(jù)類型、寄存器使用、堆積組織優(yōu)化和在一個(gè)嵌入式軟件中的參數(shù)的標(biāo)準(zhǔn)約定。開發(fā)者使用自己的匯編語(yǔ)言也可以使用 EABI 作為與兼容的編譯器生成的匯編語(yǔ)言的接口。
??兩者主要區(qū)別是,ABI是計(jì)算機(jī)上的,EABI是嵌入式平臺(tái)上(如ARM,MIPS等)。
arm-linux-gnueabi-gcc 和 arm-linux-gnueabihf-gcc
??兩個(gè)交叉編譯器分別適用于 armel 和 armhf 兩個(gè)不同的架構(gòu),armel 和 armhf 這兩種架構(gòu)在對(duì)待浮點(diǎn)運(yùn)算采取了不同的策略(有 fpu 的 arm 才能支持這兩種浮點(diǎn)運(yùn)算策略)。
??其實(shí)這兩個(gè)交叉編譯器只不過(guò)是 gcc 的選項(xiàng) -mfloat-abi 的默認(rèn)值不同。gcc 的選項(xiàng) -mfloat-abi 有三種值 soft、softfp、hard(其中后兩者都要求 arm 里有 fpu 浮點(diǎn)運(yùn)算單元,soft 與后兩者是兼容的,但 softfp 和 hard 兩種模式互不兼容):
soft: 不用fpu進(jìn)行浮點(diǎn)計(jì)算,即使有fpu浮點(diǎn)運(yùn)算單元也不用,而是使用軟件模式。
softfp: armel架構(gòu)(對(duì)應(yīng)的編譯器為 arm-linux-gnueabi-gcc )采用的默認(rèn)值,用fpu計(jì)算,但是傳參數(shù)用普通寄存器傳,這樣中斷的時(shí)候,只需要保存普通寄存器,中斷負(fù)荷小,但是參數(shù)需要轉(zhuǎn)換成浮點(diǎn)的再計(jì)算。
hard: armhf架構(gòu)(對(duì)應(yīng)的編譯器 arm-linux-gnueabihf-gcc )采用的默認(rèn)值,用fpu計(jì)算,傳參數(shù)也用fpu中的浮點(diǎn)寄存器傳,省去了轉(zhuǎn)換,性能最好,但是中斷負(fù)荷高。
把以下測(cè)試使用的C文件內(nèi)容保存成 mfloat.c:
#include <stdio.h>
int main(void)
{
double a,b,c;
a = 23.543;
b = 323.234;
c = b/a;
printf(“the 13/2 = %f\n”, c);
printf(“hello world !\n”);
return 0;
}
1、使用 arm-linux-gnueabihf-gcc 編譯,使用“-v”選項(xiàng)以獲取更詳細(xì)的信息:
arm-linux-gnueabihf-gcc -v mfloat.c
COLLECT_GCC_OPTIONS=’-v’ ‘-march=armv7-a’ ‘-mfloat-abi=hard’ ‘-mfpu=vfpv3-d16′ ‘-mthumb’
-mfloat-abi=hard
可看出使用hard硬件浮點(diǎn)模式。
2、使用 arm-linux-gnueabi-gcc 編譯:
arm-linux-gnueabi-gcc -v mfloat.c
COLLECT_GCC_OPTIONS=’-v’ ‘-march=armv7-a’ ‘-mfloat-abi=softfp’ ‘-mfpu=vfpv3-d16′ ‘-mthumb’
-mfloat-abi=softfp
可看出使用softfp模式。
搭建交叉編譯工具鏈環(huán)境
??本文使用的是X86下的Ubuntu虛擬機(jī)環(huán)境,作為64位宿主機(jī),目標(biāo)是安裝配置32位 ARM 交叉編譯工具鏈。
交叉編譯工具鏈從linaro官網(wǎng)下載,鏈接:linaro官網(wǎng)
- 下載對(duì)應(yīng)的最新版本:gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf.tar.xz
- 將工具包拷貝至 /usr/local/arm下,解壓:
sudo mkdir /usr/local/arm
sudo chmod -R 777 arm
sudo cp gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf.tar.xz /usr/local/arm/
sudo tar vxf gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf.tar.xz
- 配置交叉編譯工具鏈的環(huán)境變量:
sudo vim /etc/profile
#在末尾添加:
export PATH=$PATH:/usr/local/arm/gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf/bin
- 運(yùn)行profile文件:
source /etc/profile
- 安裝32位依賴庫(kù)
(1)想要在amd64 系統(tǒng)上編譯、鏈接32位代碼,需要安裝libc6-i386
sudo apt-get install libc6-i386
出現(xiàn)依賴問(wèn)題,例如:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-684826.html
libc6-i386 : Depends: libc6 (= 2.27-3ubuntu1) but 2.27-3ubuntu1.6 is to be installed
需要更新合適的apt源,參考:apt源適配
(2)安裝libstdc++6、lib32stdc++6庫(kù)文件文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-684826.html
sudo apt-get install libstdc++6
sudo apt-get install lib32stdc++6
- 查看安裝情況
查看交叉編譯工具版本,如如下正確顯示,則安裝配置完成:
~$ arm-linux-gnueabihf-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/usr/local/arm/gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf/bin/../libexec/gcc/arm-linux-gnueabihf/13.0.0/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: '/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/snapshots/gcc.git~master/configure' SHELL=/bin/bash --with-mpc=/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/_build/builds/destdir/x86_64-pc-linux-gnu --with-mpfr=/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/_build/builds/destdir/x86_64-pc-linux-gnu --with-gmp=/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/_build/builds/destdir/x86_64-pc-linux-gnu --with-gnu-as --with-gnu-ld --disable-libmudflap --enable-lto --enable-shared --without-included-gettext --enable-nls --with-system-zlib --disable-sjlj-exceptions --enable-gnu-unique-object --enable-linker-build-id --disable-libstdcxx-pch --enable-c99 --enable-clocale=gnu --enable-libstdcxx-debug --enable-long-long --with-cloog=no --with-ppl=no --with-isl=no --disable-multilib --with-float=hard --with-fpu=vfpv3-d16 --with-mode=thumb --with-tune=cortex-a9 --with-arch=armv7-a --enable-threads=posix --enable-multiarch --enable-libstdcxx-time=yes --enable-gnu-indirect-function --with-sysroot=/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/_build/builds/destdir/x86_64-pc-linux-gnu/arm-linux-gnueabihf/libc --enable-checking=release --disable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/home/tcwg-buildslave/workspace/tcwg-gnu-build_2/_build/builds/destdir/x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu --target=arm-linux-gnueabihf
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 13.0.0 20221001 (experimental) [master revision 5299155bb80e90df822e1eebc9f9a0c8e4505a46] (GCC)
到了這里,關(guān)于嵌入式系統(tǒng)——交叉編譯概念與環(huán)境搭建的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!