Embedded system - cross-compilation concept and environment construction

  This article belongs to the basic knowledge of embedded systems, mainly introducing the compilation process and cross-compilation. For transplanting an operating system based on an ARM core microprocessor, it is inevitable to use cross-compilation. Cross-compilation refers to the operation of compiling program code between different platforms. Different platforms have two aspects: (1) different operating systems; (2) different processor platforms, such as ARM and X86.

How the gcc compiler works

  A compiler is a tool that can edit code and translate high-level language code into machine code. For example, the written C language code is finally a .c format file; the java language code is finally a .java format file. These high-level language files cannot be composed by computers To run directly, a "translation" tool is needed to convert the high-level language into machine language that the computer can recognize. This process is decoding.
  Decoding is mainly divided into four stages: preprocessing, compiling, assembling, and linking. The executable file formed after linking is downloaded to the target OS for execution:
The general workflow of the compiler

preprocessing

First, write the simplest helloworld.c file

#include <stdio.h>
int main()
{
	print("Hello, World!");  //字符串需要""包起来
	return 0;
}

Taking gcc preprocessing as an example, it includes the following operations:

  1. Find and replace the included header file and the value defined by the macro with the final content;
  2. Automatically delete comments in code;
  3. Add line numbers and logos;
  4. Generate .i preprocessed files
gcc -E hello.c -o hello.i  #预处理命令

Generate hello.i file, view hello.i file:

# 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;
}

Compile phase

  The purpose of the compile phase is to translate the preprocessed files into assembly files. For the compiler, the compilation phase is the most complex process, which includes:

  1. lexical analysis;
  2. Gramma analysis;
  3. Semantic analysis and intermediate code generation;
  4. optimization;
  5. object code generation
gcc -S hello.i -o hello.s  #生成汇编代码
gcc -S hello.c -o hello.s  #也可以直接将.C文件编译为汇编文件

View the hello.s assembly file:

	.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

compilation stage

The assembly process of the compiler is that the as assembler converts the .s assembly file into an intermediate object file. The .s assembly code generated by the compilation process is converted into an intermediate object file of machine code. The intermediate object file is a binary file and cannot be run directly. It needs to be linked to run.

gcc -c hello.s -o hello.o

link phase

  The link is that the ld linker links one or more intermediate object files and the required static library files (.a) and dynamic library files (.so) into executable files.
Static link: link static library file, add all the code of the library file to the executable file, the generated executable file is larger, and the library file is not needed at runtime; dynamic link: the library file code is not
added to the executable file when linking In the file, when the executable file is running, there is a link file to load the library, which saves system overhead and needs to rely on the library file.
gcc hello.o -o hello

cross compile

  Cross-compilation toolchain: compiler, linker, and interpreter, mainly composed of binutils, gcc, and glibc.
  The compilation process includes functions such as preprocessing, compiling, assembling, and linking. Each sub-function is implemented by a separate tool, and together they form a complete tool set. At the same time, the compilation process is a sequential process, which involves the use order of the tools. Each tool is connected in series according to the sequence relationship to form a compilation tool chain. The cross-compilation tool chain is a complete set of tools composed of multiple sub-tools for compiling the program code of the cross-platform architecture. At the same time, it hides the details of preprocessing, compilation, assembly, linking, etc. When we specify the source file (.c), it will automatically call different subtools according to the compilation process, and automatically generate the final binary program image (.bin ).

Note: Strictly speaking, a cross-compiler just refers to the cross-compiled gcc, but in fact, for convenience, the cross-compiler we often refer to is the cross-compilation toolchain

Cross-compilation toolchain naming rules

When using a cross-compilation chain, you often see names like the following:

  • arm-linux-gnueabihf-
  • arm-none-linux-gnueabi-
  • arm-cortex_a8-linux-gnueabi-
  • mips-malta-linux-gnu-

  The naming of these cross-compilation chains usually follows certain rules: arch-vender-os-abi, each field is described as follows:
arch: target cpu architecture, such as mips, arm, x86, riscv, etc., this field is usually not omitted
vendor: Provide the vendor name or vendor-specific information of this compilation toolchain. This field is just identification information and has no practical significance. It can be none, cross, unknown or simply omitted. os: The operating system running on the target device, common ones are linux
, none (bare metal), etc.
abi: Application Binary Interface (Application Binary Interface), the specification of the library function and target image selected by the cross-compilation chain, the common values ​​of this field are abi, eabi (embedded abi), gun (glibc+oabi ), gnueabi (glibc+eabi), gnueabihf (hf means that the default compilation parameters support hardware floating-point function), etc.

  In terms of authorization, it is divided into a free authorized version and a paid authorized version.

The free version is currently provided by three mainstream tool vendors, the first is GNU (provide source code, self-compiled production), the second is Codesourcery, and the third is Linora.

The paid version includes the armcc provided by the original ARM factory, the compiler provided by IAR, etc., because these are relatively expensive and not suitable for learning users, so I will not describe them.

arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-linux-gnueabihf-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
aarch64-linux-gnu-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-none-elf-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
arm-none-eabi-gcc:是 GNU 推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。

  According to whether the operating system is supported or not, ARM GCC can be divided into supported and unsupported operating systems, such as

arm-none-eabi:这个是没有操作系统的,自然不可能支持那些跟操作系统关系密切的函数,比如fork(2)。他使用的是newlib这个专用于嵌入式系统的C库。
arm-none-linux-eabi:用于Linux的,使用Glibc

Example
1. arm-none-eabi-gcc (ARM architecture, no vendor, not target an operating system, complies with the ARM EABI)
  is used to compile bare-metal systems of the ARM architecture (including ARM Linux boot and kernel, not suitable for compiling Linux Application), generally suitable for chips with ARM7, Cortex-M and Cortex-R cores, so it does not support functions closely related to the operating system, such as fork(2), which uses newlib, which is dedicated to embedded systems C library.
2. arm-none-linux-gnueabi-gcc (ARM architecture, no vendor, creates binaries that run on the Linux operating system, and uses the GNU EABI) is mainly used for Linux systems based on ARM architecture, and can be used to
  compile ARM architecture u-boot, Linux kernel, linux applications, etc. arm-none-linux-gnueabi is based on GCC, uses the Glibc library, and has been optimized by Codesourcery. The floating-point operations of the arm-none-linux-gnueabi-xxx cross-compiler tools are excellent. Generally ARM9, ARM11, Cortex-A core, with Linux operating system will be used.
3. arm-eabi-gcc
  Android ARM compiler.
4. armcc
  The compilation tool launched by ARM has similar functions to arm-none-eabi, and can compile bare-metal programs (u-boot, kernel), but cannot compile Linux applications. armcc is generally used together with ARM development tools. The compilers in Keil MDK, ADS, RVDS and DS-5 are all armcc, so armcc compilers are charged.
5. arm-none-uclinuxeabi-gcc and arm-none-symbianelf-gcc
arm-none-uclinuxeabi are used for uCLinux and use Glibc.
arm-none-symbianelf for symbian.

Codesourcery
  The product launched by Codesourcery is called Sourcery G++ Lite Edition. The command-line-based compiler is free and can be downloaded from the official website. The IDE and debug tools included in it are charged. Of course, there is also a 30-day trial version. Currently CodeSourcery has been acquired by Mentor Graphics, so the original website style has all changed to Mentor style, but Sourcery G++ Lite Edition can also be downloaded for free after registration.
  Codesourcery has been doing the development and optimization of ARM target GCC. Its ARM GCC is currently very good in the market. Many patches may not be accepted by gcc, so it should be used directly (and it provides [mingw cross Compiled] and the binary version under Linux are more convenient; if you don’t have time and interest, it is not recommended to download the src source package and compile it yourself. The manual execution of the part is time-consuming and labor-intensive. If you want to know the details, you don’t need to compile it yourself, just see what steps it uses to build it. If you are interested in cross-compilers.

ABI and EABI

  • ABI: Application Binary Interface (ABI) for the ARM Architecture. In computing, an application binary interface describes the low-level interface between an application program (or other type) and the operating system or other applications.
  • EABI: Embedded ABI. The Embedded Application Binary Interface specifies standard conventions for file formats, data types, register usage, stack organization optimizations, and parameters within an embedded software. Developers using their own assembly language can also use EABI as an interface to assembly language generated by a compatible compiler.
      The main difference between the two is that ABI is on the computer, and EABI is on the embedded platform (such as ARM, MIPS, etc.).


  The two cross compilers arm-linux-gnueabi-gcc and arm-linux-gnueabihf- gcc are suitable for two different architectures of armel and armhf respectively. The two architectures of armel and armhf adopt different strategies for floating-point operations ( The arm with fpu can support these two floating-point arithmetic strategies).
  In fact, the two cross-compilers are just different default values ​​of the gcc option -mfloat-abi. The gcc option -mfloat-abi has three values: soft, softfp, and hard (the latter two require an fpu floating-point unit in the arm, soft is compatible with the latter two, but the two modes of softfp and hard are incompatible with each other ):
soft: Do not use fpu for floating-point calculations, even if there is an fpu floating-point unit, but use software mode.
softfp: The default value adopted by the armel architecture (the corresponding compiler is arm-linux-gnueabi-gcc), which is calculated by fpu, but the parameters are passed by ordinary registers. When interrupting, only ordinary registers need to be saved, and the interrupt load is small. But the parameters need to be converted to floating point for recalculation.
hard: the default value adopted by the armhf architecture (corresponding compiler arm-linux-gnueabihf-gcc), calculated by fpu, and the parameters are also passed by the floating-point registers in fpu, which saves the conversion and has the best performance, but the interrupt load high.

Save the content of the C file used in the following tests as 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. Compile with arm-linux-gnueabihf-gcc, use the "-v" option to get more detailed information:

arm-linux-gnueabihf-gcc -v mfloat.c
COLLECT_GCC_OPTIONS=’-v’ ‘-march=armv7-a’ ‘-mfloat-abi=hard’ ‘-mfpu=vfpv3-d16′ ‘-mthumb’
-mfloat-abi=hard

It can be seen that the hard hardware floating point mode is used.

2. Compile with 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

It can be seen that softfp mode is used.

Build a cross-compilation toolchain environment

  This article uses the Ubuntu virtual machine environment under X86 as a 64-bit host, and the goal is to install and configure a 32-bit ARM cross-compilation toolchain.
Download the cross-compilation toolchain from linaro official website, link: linaro official website

  1. Download the corresponding latest version: gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf.tar.xz
  2. Copy the toolkit to /usr/local/arm and unzip it:
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
  1. Configure environment variables for the cross-compilation toolchain:
 sudo vim /etc/profile
 #在末尾添加:
 export PATH=$PATH:/usr/local/arm/gcc-linaro-13.0.0-2022.10-x86_64_arm-linux-gnueabihf/bin
  1. Run the profile file:
source /etc/profile
  1. Install 32-bit dependent libraries

(1) If you want to compile and link 32-bit code on the amd64 system, you need to install libc6-i386

sudo apt-get install libc6-i386

Dependency issues arise, such as:

libc6-i386 : Depends: libc6 (= 2.27-3ubuntu1) but 2.27-3ubuntu1.6 is to be installed

Need to update the appropriate apt source, refer to: apt source adaptation
(2) Install libstdc++6, lib32stdc++6 library files

sudo apt-get install libstdc++6
sudo apt-get install lib32stdc++6
  1. Check the installation status
    Check the version of the cross-compilation tool. If it is displayed correctly as follows, the installation and configuration are complete:
~$ 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) 

Guess you like

Origin blog.csdn.net/weixin_43229184/article/details/127217836