Bootstrap

c文件的编译,汇编,基础知识


前言

#include <stdio.h>
int main()
 {
 printf("hello, world\n");
 }

从这个最简单的例子开始分析


一、预编译

gcc -E hello.c -o hello.i
# 0 "helllo.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 0 "<command-line>" 2
# 1 "helllo.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/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
# 402 "/usr/include/features.h" 3 4
# 1 "/usr/include/features-time64.h" 1 3 4
# 20 "/usr/include/features-time64.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 21 "/usr/include/features-time64.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 1 3 4
# 19 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 20 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 2 3 4
# 22 "/usr/include/features-time64.h" 2 3 4
# 403 "/usr/include/features.h" 2 3 4
# 510 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 730 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 731 "/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
# 732 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 511 "/usr/include/features.h" 2 3 4
# 534 "/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
# 535 "/usr/include/features.h" 2 3 4
# 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
# 29 "/usr/include/stdio.h" 2 3 4





# 1 "/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h" 1 3 4
# 214 "/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h" 3 4

# 214 "/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 35 "/usr/include/stdio.h" 2 3 4


# 1 "/usr/lib/gcc/x86_64-linux-gnu/14/include/stdarg.h" 1 3 4
# 40 "/usr/lib/gcc/x86_64-linux-gnu/14/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 38 "/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
# 1 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 1 3 4
# 19 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 20 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 2 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 __int8_t __int_least8_t;
typedef __uint8_t __uint_least8_t;
typedef __int16_t __int_least16_t;
typedef __uint16_t __uint_least16_t;
typedef __int32_t __int_least32_t;
typedef __uint32_t __uint_least32_t;
typedef __int64_t __int_least64_t;
typedef __uint64_t __uint_least64_t;



typedef long int __quad_t;
typedef unsigned long int __u_quad_t;







typedef long int __intmax_t;
typedef unsigned long int __uintmax_t;
# 141 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/typesizes.h" 1 3 4
# 142 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/time64.h" 1 3 4
# 143 "/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 long int __suseconds64_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;
# 40 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 1 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;
# 6 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 2 3 4




typedef struct _G_fpos_t
{
  __off_t __pos;
  __mbstate_t __state;
} __fpos_t;
# 41 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 3 4
typedef struct _G_fpos64_t
{
  __off64_t __pos;
  __mbstate_t __state;
} __fpos64_t;
# 42 "/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;
# 43 "/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;
# 44 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 1 3 4
# 35 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 3 4
struct _IO_FILE;
struct _IO_marker;
struct _IO_codecvt;
struct _IO_wide_data;




typedef void _IO_lock_t;





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;







  __off64_t _offset;

  struct _IO_codecvt *_codecvt;
  struct _IO_wide_data *_wide_data;
  struct _IO_FILE *_freeres_list;
  void *_freeres_buf;
  struct _IO_FILE **_prevchain;
  int _mode;

  char _unused2[15 * sizeof (int) - 5 * sizeof (void *)];
};
# 45 "/usr/include/stdio.h" 2 3 4


# 1 "/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h" 1 3 4
# 27 "/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h" 3 4
typedef __ssize_t cookie_read_function_t (void *__cookie, char *__buf,
                                          size_t __nbytes);







typedef __ssize_t cookie_write_function_t (void *__cookie, const char *__buf,
                                           size_t __nbytes);







typedef int cookie_seek_function_t (void *__cookie, __off64_t *__pos, int __w);


typedef int cookie_close_function_t (void *__cookie);






typedef struct _IO_cookie_io_functions_t
{
  cookie_read_function_t *read;
  cookie_write_function_t *write;
  cookie_seek_function_t *seek;
  cookie_close_function_t *close;
} cookie_io_functions_t;
# 48 "/usr/include/stdio.h" 2 3 4





typedef __gnuc_va_list va_list;
# 64 "/usr/include/stdio.h" 3 4
typedef __off_t off_t;
# 78 "/usr/include/stdio.h" 3 4
typedef __ssize_t ssize_t;






typedef __fpos_t fpos_t;
# 129 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/stdio_lim.h" 1 3 4
# 130 "/usr/include/stdio.h" 2 3 4
# 149 "/usr/include/stdio.h" 3 4
extern FILE *stdin;
extern FILE *stdout;
extern 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__));
# 184 "/usr/include/stdio.h" 3 4
extern int fclose (FILE *__stream) __attribute__ ((__nonnull__ (1)));
# 194 "/usr/include/stdio.h" 3 4
extern FILE *tmpfile (void)
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;
# 211 "/usr/include/stdio.h" 3 4
extern char *tmpnam (char[20]) __attribute__ ((__nothrow__ , __leaf__)) ;




extern char *tmpnam_r (char __s[20]) __attribute__ ((__nothrow__ , __leaf__)) ;
# 228 "/usr/include/stdio.h" 3 4
extern char *tempnam (const char *__dir, const char *__pfx)
   __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (__builtin_free, 1)));






extern int fflush (FILE *__stream);
# 245 "/usr/include/stdio.h" 3 4
extern int fflush_unlocked (FILE *__stream);
# 264 "/usr/include/stdio.h" 3 4
extern FILE *fopen (const char *__restrict __filename,
      const char *__restrict __modes)
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;




extern FILE *freopen (const char *__restrict __filename,
        const char *__restrict __modes,
        FILE *__restrict __stream) __attribute__ ((__nonnull__ (3)));
# 299 "/usr/include/stdio.h" 3 4
extern FILE *fdopen (int __fd, const char *__modes) __attribute__ ((__nothrow__ , __leaf__))
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;





extern FILE *fopencookie (void *__restrict __magic_cookie,
     const char *__restrict __modes,
     cookie_io_functions_t __io_funcs) __attribute__ ((__nothrow__ , __leaf__))
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;




extern FILE *fmemopen (void *__s, size_t __len, const char *__modes)
  __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;




extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__ , __leaf__))
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;
# 334 "/usr/include/stdio.h" 3 4
extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__ , __leaf__))
  __attribute__ ((__nonnull__ (1)));



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




extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
         size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));


extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));







extern int fprintf (FILE *__restrict __stream,
      const char *__restrict __format, ...) __attribute__ ((__nonnull__ (1)));




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) __attribute__ ((__nonnull__ (1)));




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)));





extern int vasprintf (char **__restrict __ptr, const char *__restrict __f,
        __gnuc_va_list __arg)
     __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 0))) ;
extern int __asprintf (char **__restrict __ptr,
         const char *__restrict __fmt, ...)
     __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 3))) ;
extern int asprintf (char **__restrict __ptr,
       const char *__restrict __fmt, ...)
     __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 3))) ;




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, ...) __attribute__ ((__nonnull__ (1)));




extern int scanf (const char *__restrict __format, ...) ;

extern int sscanf (const char *__restrict __s,
     const char *__restrict __format, ...) __attribute__ ((__nothrow__ , __leaf__));





# 1 "/usr/include/x86_64-linux-gnu/bits/floatn.h" 1 3 4
# 120 "/usr/include/x86_64-linux-gnu/bits/floatn.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/floatn-common.h" 1 3 4
# 24 "/usr/include/x86_64-linux-gnu/bits/floatn-common.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
# 25 "/usr/include/x86_64-linux-gnu/bits/floatn-common.h" 2 3 4
# 121 "/usr/include/x86_64-linux-gnu/bits/floatn.h" 2 3 4
# 438 "/usr/include/stdio.h" 2 3 4
# 463 "/usr/include/stdio.h" 3 4
extern int fscanf (FILE *__restrict __stream, const char *__restrict __format, ...) __asm__ ("" "__isoc99_fscanf")

                                __attribute__ ((__nonnull__ (1)));
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__))

                      ;
# 490 "/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))) __attribute__ ((__nonnull__ (1)));





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)));
# 540 "/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))) __attribute__ ((__nonnull__ (1)));
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)));
# 575 "/usr/include/stdio.h" 3 4
extern int fgetc (FILE *__stream) __attribute__ ((__nonnull__ (1)));
extern int getc (FILE *__stream) __attribute__ ((__nonnull__ (1)));





extern int getchar (void);






extern int getc_unlocked (FILE *__stream) __attribute__ ((__nonnull__ (1)));
extern int getchar_unlocked (void);
# 600 "/usr/include/stdio.h" 3 4
extern int fgetc_unlocked (FILE *__stream) __attribute__ ((__nonnull__ (1)));
# 611 "/usr/include/stdio.h" 3 4
extern int fputc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));
extern int putc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));





extern int putchar (int __c);
# 627 "/usr/include/stdio.h" 3 4
extern int fputc_unlocked (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));







extern int putc_unlocked (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));
extern int putchar_unlocked (int __c);






extern int getw (FILE *__stream) __attribute__ ((__nonnull__ (1)));


extern int putw (int __w, FILE *__stream) __attribute__ ((__nonnull__ (2)));







extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
     __attribute__ ((__access__ (__write_only__, 1, 2))) __attribute__ ((__nonnull__ (3)));
# 689 "/usr/include/stdio.h" 3 4
extern __ssize_t __getdelim (char **__restrict __lineptr,
                             size_t *__restrict __n, int __delimiter,
                             FILE *__restrict __stream) __attribute__ ((__nonnull__ (4)));
extern __ssize_t getdelim (char **__restrict __lineptr,
                           size_t *__restrict __n, int __delimiter,
                           FILE *__restrict __stream) __attribute__ ((__nonnull__ (4)));


extern __ssize_t getline (char **__restrict __lineptr,
                          size_t *__restrict __n,
                          FILE *__restrict __stream) __attribute__ ((__nonnull__ (3)));







extern int fputs (const char *__restrict __s, FILE *__restrict __stream)
  __attribute__ ((__nonnull__ (2)));





extern int puts (const char *__s);






extern int ungetc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));






extern size_t fread (void *__restrict __ptr, size_t __size,
       size_t __n, FILE *__restrict __stream)
  __attribute__ ((__nonnull__ (4)));




extern size_t fwrite (const void *__restrict __ptr, size_t __size,
        size_t __n, FILE *__restrict __s) __attribute__ ((__nonnull__ (4)));
# 756 "/usr/include/stdio.h" 3 4
extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,
         size_t __n, FILE *__restrict __stream)
  __attribute__ ((__nonnull__ (4)));
extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size,
          size_t __n, FILE *__restrict __stream)
  __attribute__ ((__nonnull__ (4)));







extern int fseek (FILE *__stream, long int __off, int __whence)
  __attribute__ ((__nonnull__ (1)));




extern long int ftell (FILE *__stream) __attribute__ ((__nonnull__ (1)));




extern void rewind (FILE *__stream) __attribute__ ((__nonnull__ (1)));
# 793 "/usr/include/stdio.h" 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence)
  __attribute__ ((__nonnull__ (1)));




extern __off_t ftello (FILE *__stream) __attribute__ ((__nonnull__ (1)));
# 819 "/usr/include/stdio.h" 3 4
extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos)
  __attribute__ ((__nonnull__ (1)));




extern int fsetpos (FILE *__stream, const fpos_t *__pos) __attribute__ ((__nonnull__ (1)));
# 850 "/usr/include/stdio.h" 3 4
extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));

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

extern int ferror (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));



extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));
extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));
extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));







extern void perror (const char *__s) __attribute__ ((__cold__));




extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));




extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));
# 887 "/usr/include/stdio.h" 3 4
extern int pclose (FILE *__stream) __attribute__ ((__nonnull__ (1)));





extern FILE *popen (const char *__command, const char *__modes)
  __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (pclose, 1))) ;






extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__))
  __attribute__ ((__access__ (__write_only__, 1)));
# 931 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));



extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));


extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));
# 949 "/usr/include/stdio.h" 3 4
extern int __uflow (FILE *);
extern int __overflow (FILE *, int);
# 973 "/usr/include/stdio.h" 3 4

# 2 "helllo.c" 2

# 2 "helllo.c"
int main()
 {
 printf("hello, world\n");
 }

预编译过程是C语言编译过程中的第一个阶段,它处理源代码文件(.c 文件)并生成一个中间文件(.i 文件),这个中间文件包含了预编译的结果。

  1. gcc -E hello.c -o hello.i

    • 这个命令告诉GCC编译器只执行预编译阶段,并将结果输出到 hello.i 文件中。
  2. # 1 “hello.c”

    • 这是一个预编译器标记,表示预编译器开始处理 hello.c 文件。
  3. # 1 “”

    • 这表示预编译器正在处理内置的宏定义和预编译指令。
  4. # 1 “”

    • 这表示预编译器正在处理从命令行传递给编译器的参数。
  5. *extern int printf (const char __restrict __format, …);

    • 这是 printf 函数的声明,它可能来自包含的头文件(如 <stdio.h>)。预编译器会处理所有的 #include 指令,将相应的头文件内容插入到源代码中。
  6. main() {

    • 这是 main 函数的定义开始。
  7. printf(“hello, world\n”);

    • 这是 main 函数中的一条语句,调用 printf 函数打印 “hello, world\n”。
  8. }

    • 这是 main 函数的定义结束。

这些行号和文件名标记是由预处理器添加的,以便在编译时跟踪源代码的位置。

  1. 文件和命令行信息

    • # 0 "helllo.c":表示当前处理的文件是hello.c
    • # 0 "<built-in>":表示预处理器正在处理内置的宏定义。
    • # 0 "<command-line>":表示预处理器正在处理命令行参数。
  2. 头文件包含

    • # 1 "/usr/include/stdc-predef.h" 1 3 4:表示预处理器开始处理/usr/include/stdc-predef.h头文件,1 3 4表示宏定义__STDC____STDC_VERSION____STDC_UTF_16__被定义。
    • # 0 "<command-line>" 2:表示预处理器回到了命令行模式,2表示这是第二个指令。
    • # 1 "hello.c":表示预处理器回到了hello.c文件。
  3. 标准库头文件

    • # 1 "/usr/include/stdio.h" 1 3 4:表示预处理器开始处理/usr/include/stdio.h头文件。
    • # 28 "/usr/include/stdio.h" 3 4:表示预处理器在stdio.h文件的第28行。
  4. 系统头文件

    • # 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4:表示预处理器开始处理系统特定的头文件libc-header-start.h
  5. 类型定义

    • typedef long unsigned int size_t;:定义了size_t类型,通常用于表示对象的大小。
    • typedef __builtin_va_list __gnuc_va_list;:定义了__gnuc_va_list类型,用于处理可变参数列表。
  6. 基本数据类型定义

    • typedef unsigned char __u_char;:定义了__u_char类型,表示无符号字符。
    • typedef signed char __int8_t;:定义了__int8_t类型,表示有符号的8位整数。
    • 其他类似的行定义了不同大小和符号的整数类型。
  7. 文件结构定义

    • struct _IO_FILE:定义了_IO_FILE结构,它是FILE结构的内部表示,用于标准I/O操作。
  8. I/O函数类型定义

    • typedef struct _IO_cookie_io_functions_t:定义了I/O函数类型的结构。
  9. 宏和函数声明

    • extern int remove (const char *__filename) __attribute__ ((__nothrow__ , __leaf__));:声明了remove函数,用于删除文件。
    • extern int rename (const char *__old, const char *__new) __attribute__ ((__nothrow__ , __leaf__));:声明了rename函数,用于重命名文件。
  10. 主函数

    • int main():定义了main函数,程序的入口点。
    • printf("hello, world\n");:调用printf函数打印"hello, world"。
    • }main函数的结束。

预编译过程的具体处理内容如下:

  • 处理预编译指令:预编译器会查找以 # 开头的指令,并根据这些指令执行相应的操作。

  • 宏定义的展开:预编译器会删除所有的 #define 指令,并展开代码中的宏定义。例如,如果在代码中有 #define MAX 100,那么预编译器会将所有的 MAX 替换为 100

  • 条件预编译指令:预编译器会处理 #if#ifdef#elif#else#endif 等条件预编译指令,根据这些指令决定是否包含某些代码。

  • 包含头文件:预编译器会处理 #include 指令,将被包含的文件内容插入到该指令的位置。这个过程是递归的,意味着如果被包含的文件中还有 #include 指令,预编译器会继续处理这些指令。

  • 删除注释:预编译器会删除源代码中的所有注释(///* */)。

  • 添加行号和文件名标号:预编译器会在输出的 .i 文件中添加行号和文件名信息,以便于调试和错误报告。

  • 保留 #pragma 编译器指令#pragma 指令是编译器特定的指令,预编译器会保留这些指令,以便后续的编译阶段处理。

二、编译阶段

gcc -S hello.c -o helo.s
.file	"helllo.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), %rax
	movq	%rax, %rdi
	call	puts@PLT
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Debian 14.2.0-6) 14.2.0"
	.section	.note.GNU-stack,"",@progbits

这段代码是一个用GCC编译器生成的x86-64位Linux系统下的C语言程序的汇编代码。程序的功能是打印 “hello, world” 到标准输出。下面是对这段汇编代码的详细解释:

  1. .file "helllo.c"

    • 这是一个文件标识符,用于调试信息,表明这段代码来自源文件 “helllo.c”。
  2. .text

    • 这是一个指令,告诉汇编器接下来的代码应该放在程序的文本段(代码段)。
  3. .section .rodata

    • 指定接下来的数据应该放在只读数据段(.rodata),通常用于存放程序中的常量。
  4. .LC0:

    • 定义了一个标签(label),用于标识常量字符串 “hello, world”。
  5. .string "hello, world"

    • 定义了一个字符串常量 “hello, world”。
  6. .text

    • 再次指定接下来的代码应该放在程序的文本段。
  7. .globl main

    • 声明 main 函数是全局符号,意味着它可以被其他文件引用。
  8. .type main, @function

    • 指定 main 是一个函数类型。
  9. main:

    • main 函数的开始。
  10. .LFB0:

    • 定义了一个标签,用于函数的开始。
  11. .cfi_startproc.cfi_def_cfa_offset.cfi_offset.cfi_def_cfa_register

    • 这些指令是调用帧信息(Call Frame Information)的一部分,用于异常处理和调试。它们定义了栈帧和寄存器的状态。
  12. pushq %rbp

    • 将基指针(rbp)压入栈中,保存当前函数的栈帧指针。
  13. movq %rsp, %rbp

    • 将栈指针(rsp)的值移动到基指针(rbp),设置新的栈帧。
  14. leaq .LC0(%rip), %rax

    • 将字符串 “hello, world” 的地址加载到寄存器 rax 中。
  15. movq %rax, %rdi

    • rax 寄存器的值(字符串地址)移动到参数寄存器 rdi 中,准备调用 puts 函数。
  16. call puts@PLT

    • 调用标准库函数 puts@PLT 表示这是一个位置无关代码(Position Independent Code)的间接跳转。
  17. movl $0, %eax

    • 将立即数0移动到寄存器 eax 中,准备返回值。在x86-64位系统调用约定中,eax 用于存储函数的返回值。
  18. popq %rbp

    • 将之前压入栈的基指针值弹出,恢复到调用者的栈帧。
  19. ret

    • 返回到调用者。
  20. .cfi_endproc

    • 标记函数的结束。
  21. .LFE0:

    • 定义了函数的结束标签。
  22. .size main, .-main

    • 指定 main 函数的大小,从 main 标签到 .LFE0 标签。
  23. .ident "GCC: (Debian 14.2.0-6) 14.2.0"

    • 这是一个版本标识符,表明这段代码是由GCC编译器版本14.2.0-6编译的。
  24. .section .note.GNU-stack,"",@progbits

    • 指定接下来的数据应该放在 .note.GNU-stack 段,这是一个GNU特有的段,用于存储栈信息。

这段汇编代码展示了GCC编译器如何将C语言代码转换为机器代码,并包含了用于调试和异常处理的额外信息。


三、汇编

1, objdump的用法

当然,以下是 objdump 工具中每个选项的详细解释:

  1. -a, --archive-headers
    这个选项用于显示归档文件(如 .a 文件)的头部信息,包括归档的成员列表。

  2. -f, --file-headers
    显示二进制文件的整体文件头信息,这通常包括文件的类型、架构、版本等。

  3. -p, --private-headers
    显示特定于对象文件格式的文件头内容,这些信息通常不是标准的 ELF 头信息。

  4. -P, --private=OPT,OPT…
    类似于 --private-headers,但允许你指定特定的选项来显示对象格式特有的内容。

  5. -h, --[section-]headers
    显示所有节(section)的头部信息,包括节的名字、大小、位置等。

  6. -x, --all-headers
    显示所有可用的头部信息,包括文件头、节头等。

  7. -d, --disassemble
    反汇编可执行的节(section),并显示汇编指令。

  8. -D, --disassemble-all
    反汇编所有节,而不仅仅是可执行的节。

  9. –disassemble=
    仅反汇编从指定符号 <sym> 开始的代码。

  10. -S, --source
    混合显示源代码和对应的反汇编代码。

  11. -s, --full-contents
    显示所有请求节的完整内容,包括未初始化的数据。

  12. -Z, --decompress
    在显示节的内容之前,先对节进行解压缩。

  13. -g, --debugging
    显示对象文件中的调试信息。

  14. -e, --debugging-tags
    以 ctags 风格显示调试信息。

  15. -G, --stabs
    以原始形式显示任何 STABS 调试信息。

  16. -W, --dwarf
    显示 DWARF 调试节的内容,可以指定多个子选项来过滤显示的内容。

  17. -Wk,–dwarf=links
    显示链接到独立调试文件的节内容。

  18. -WK,–dwarf=follow-links
    默认选项,跟随链接到独立的调试信息文件。

  19. -WN,–dwarf=no-follow-links
    不跟随链接到独立的调试信息文件。

  20. -L, --process-links
    显示分离的调试信息文件中非调试节的内容。

  21. -t, --syms
    显示符号表的内容,包括符号名称、地址、大小等。

  22. -T, --dynamic-syms
    显示动态符号表的内容。

  23. -r, --reloc
    显示文件中的重定位条目,这些条目用于链接时的地址调整。

  24. -R, --dynamic-reloc
    显示动态重定位条目。

  25. @
    从一个文件中读取 objdump 选项。

  26. -v, --version
    显示 objdump 程序的版本号。

  27. -i, --info
    列出 objdump 支持的对象格式和架构。

  28. -H, --help
    显示帮助信息。

  29. -b, --target=BFDNAME
    指定目标对象格式,BFDNAME 是 Binary File Descriptor 的名称。

  30. -m, --architecture=MACHINE
    指定目标架构。

  31. -j, --section=NAME
    仅显示指定节的信息。

  32. -M, --disassembler-options=OPT
    将文本选项 OPT 传递给反汇编器。

  33. -EB, --endian=big
    假设反汇编时使用大端格式。

  34. -EL, --endian=little
    假设反汇编时使用小端格式。

  35. –file-start-context
    -S 选项一起使用时,包括从文件开始的上下文。

  36. -I, --include=DIR
    添加 DIR 到搜索源文件的目录列表。

  37. -l, --line-numbers
    在输出中包含行号和文件名。

  38. -F, --file-offsets
    在显示信息时包含文件偏移量。

  39. -C, --demangle[=STYLE]
    解码 mangled/processed 符号名称,可以指定不同的样式。

  40. -w, --wide
    格式化输出以适应超过80列的显示。

  41. -U, --disassemble-zeroes
    在反汇编时不跳过零块。

  42. -z, --disassemble-zeroes
    -U 选项。

  43. –unicode=[default|locale|invalid|hex|escape|highlight]
    控制 UTF-8 unicode 字符的显示方式。

  44. –start-address=ADDR
    仅处理地址大于等于 ADDR 的数据。

  45. –stop-address=ADDR
    仅处理地址小于 ADDR 的数据。

  46. –no-addresses
    在反汇编时不打印地址。

  47. –prefix-addresses
    在反汇编时打印完整的地址。

  48. –[no-]show-raw-insn
    显示汇编指令旁边的十六进制代码。

  49. –insn-width=WIDTH
    在反汇编时,每行显示 WIDTH 字节。

  50. –adjust-vma=OFFSET
    对所有显示的节地址添加偏移量 OFFSET。

  51. –show-all-symbols
    在反汇编时显示给定地址的所有符号。

  52. –special-syms
    在符号转储中包括特殊符号。

  53. –inlines
    打印源代码行的所有内联。

  54. –prefix=PREFIX
    -S 选项添加绝对路径前缀。

  55. –prefix-strip=LEVEL
    -S 选项剥离初始目录名称。

  56. –dwarf-depth=N
    不显示深度为 N 或更大的 DIE。

  57. –dwarf-start=N
    从偏移量 N 开始显示 DIE。

  58. –dwarf-check
    进行额外的 DWARF 一致性检查。

  59. –ctf-parent=NAME
    使用 CTF 归档成员 NAME 作为 CTF 父项。

  60. –visualize-jumps
    通过绘制 ASCII 线条来可视化跳转。

  61. –visualize-jumps=color
    在 ASCII 线条中使用颜色。

  62. –visualize-jumps=extended-color
    使用扩展的 8 位颜色代码。

  63. –visualize-jumps=off
    禁用跳转可视化。

  64. –disassembler-color=off
    禁用反汇编器的颜色输出。

  65. –disassembler-color=terminal
    如果显示在终端上,则启用反汇编器的颜色输出。

  66. –disassembler-color=on
    启用反汇编器的颜色输出。

  67. –disassembler-color=extended
    在反汇编器输出中使用 8 位颜色。

这些选项可以组合使用,以获取所需的特定信息。

2,objdump 举例

objdump -f hello.o

hello.o:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
  1. hello.o: 表示文件名。
  2. file format elf64-x86-64 表示这个文件是一个 64 位的 ELF(Executable and Linkable Format)格式文件,适用于 x86-64 架构。
  3. architecture: i386:x86-64 表示目标文件是为 x86-64 架构编译的,这是 Intel 64 位架构的另一种称呼。
  4. flags 0x00000011: 表示文件的一些标志,这里 0x11 表示文件包含重定位信息(HAS_RELOC)和符号表(HAS_SYMS)。
  5. HAS_RELOC 表示目标文件包含重定位入口,这些入口在链接时用于确定如何修改代码和数据,以便它们在内存中的最终位置。
  6. HAS_SYMS 表示目标文件包含符号表,符号表包含了函数、变量等符号的信息,这些信息在链接时用于解析不同目标文件之间的引用。
  7. start address 0x0000000000000000 表示这个目标文件的起始地址是 0,这通常是未链接的程序的默认起始地址,实际的起始地址会在程序被链接并加载到内存时确定。
└─$ objdump -h hello.o

hello.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000001a  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  0000005a  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  0000005a  2**0
                  ALLOC
  3 .rodata       0000000d  0000000000000000  0000000000000000  0000005a  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000001f  0000000000000000  0000000000000000  00000067  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000086  2**0
                  CONTENTS, READONLY
  6 .eh_frame     00000038  0000000000000000  0000000000000000  00000088  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
   

这个 objdump -h 命令的输出显示了 hello.o 文件中的各个节(Sections)的详细信息。下面是每个节的解释:

  1. Idx: 节的索引编号。
  2. Name: 节的名称。
  3. Size: 节的大小,单位是字节。
  4. VMA (Virtual Memory Address): 节在虚拟内存中的地址。
  5. LMA (Load Memory Address): 节在文件中的加载地址。
  6. File off: 节在文件中的偏移量。
  7. Algn: 节的对齐方式,表示为2的幂。

现在,让我们逐一解释这些节:

  • .text: 这是代码段,包含了程序的机器代码。它被标记为 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE,意味着它包含实际的数据内容,会被分配内存,会被加载到内存中,包含重定位信息,是只读的,并且是代码。

    • Size: 26字节
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 64字节(从文件开头计算)
    • Algn: 1(即2^0,不需要特别的对齐)
  • .data: 这是数据段,用于存储初始化的全局变量和静态变量。

    • Size: 0字节(空)
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 90字节
    • Algn: 1
  • .bss: 这是未初始化的全局变量和静态变量的存储区域。

    • Size: 0字节(空)
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 90字节
    • Algn: 1
  • .rodata: 这是只读数据段,用于存储程序中的只读数据,如字符串常量。

    • Size: 13字节
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 90字节
    • Algn: 1
  • .comment: 这是一个特殊的节,用于存储编译器生成的注释信息。

    • Size: 31字节
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 103字节
    • Algn: 1
  • .note.GNU-stack: 这是一个GNU特有的节,用于指定堆栈的执行权限。如果这个节存在,通常意味着堆栈是可执行的。

    • Size: 0字节(空)
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 119字节
    • Algn: 1
  • .eh_frame: 这是异常处理帧信息,用于C++异常处理和堆栈展开。

    • Size: 56字节
    • VMA: 0x0000000000000000
    • LMA: 0x0000000000000000
    • File off: 120字节
    • Algn: 8(即2^3)

这些节是目标文件的基本组成部分,它们在链接过程中会被合并到最终的可执行文件或共享库中。

└─$ objdump -x hello.o 

hello.o:     file format elf64-x86-64
hello.o
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000001a  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  0000005a  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  0000005a  2**0
                  ALLOC
  3 .rodata       0000000d  0000000000000000  0000000000000000  0000005a  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000001f  0000000000000000  0000000000000000  00000067  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000086  2**0
                  CONTENTS, READONLY
  6 .eh_frame     00000038  0000000000000000  0000000000000000  00000088  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 helllo.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .rodata        0000000000000000 .rodata
0000000000000000 g     F .text  000000000000001a main
0000000000000000         *UND*  0000000000000000 puts


RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000007 R_X86_64_PC32     .rodata-0x0000000000000004
000000000000000f R_X86_64_PLT32    puts-0x0000000000000004


RELOCATION RECORDS FOR [.eh_frame]:
OFFSET           TYPE              VALUE
0000000000000020 R_X86_64_PC32     .text
  1. 文件格式和架构

    • elf64-x86-64:文件是64位的ELF格式,适用于x86-64架构。
    • HAS_RELOC, HAS_SYMS:文件包含重定位信息和符号表。
  2. 节信息

    • .text:代码段,大小为26字节,包含指令代码。
    • .data:数据段,大小为0字节,用于存储初始化的全局变量和静态变量。
    • .bss:未初始化数据段,大小为0字节,用于存储未初始化的全局变量和静态变量。
    • .rodata:只读数据段,大小为13字节,通常包含常量字符串。
    • .comment:注释段,大小为31字节,包含编译器生成的注释信息。
    • .note.GNU-stack:GNU栈注解,大小为0字节,通常用于堆栈不可执行标记。
    • .eh_frame:异常处理帧,大小为56字节,用于C++异常处理。
  3. 符号表

    • *ABS*:绝对位置,表示符号不依赖于任何节。
    • hello.c:源文件名。
    • .text.rodata:节名称。
    • main:全局符号,函数 main 的入口点,位于 .text 节。
    • *UND*:未定义,表示 puts 函数在本文件中未定义,需要在链接时解析。
  4. 重定位记录

    • .text 节的重定位记录:
      • 0000000000000007 R_X86_64_PC32 .rodata-0x0000000000000004:32位PC相对地址重定位,指向 .rodata 节的某个位置。
      • 000000000000000f R_X86_64_PLT32 puts-0x0000000000000004:32位过程链接表(PLT)重定位,指向 puts 函数。
    • .eh_frame 节的重定位记录:
      • 0000000000000020 R_X86_64_PC32 .text:32位PC相对地址重定位,指向 .text 节。
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:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax        # b <main+0xb>
   b:   48 89 c7                mov    %rax,%rdi
   e:   e8 00 00 00 00          call   13 <main+0x13>
  13:   b8 00 00 00 00          mov    $0x0,%eax
  18:   5d                      pop    %rbp
  19:   c3                      ret
                                                                                                                                                                                            
(.venv) ┌──(.venv)─(zqy㉿kali)-[~/tonlearn/c_learn]
└─$ objdump -s hello.o

hello.o:     file format elf64-x86-64

Contents of section .text:
 0000 554889e5 488d0500 00000048 89c7e800  UH..H......H....
 0010 000000b8 00000000 5dc3               ........].      
Contents of section .rodata:
 0000 68656c6c 6f2c2077 6f726c64 00        hello, world.   
Contents of section .comment:
 0000 00474343 3a202844 65626961 6e203134  .GCC: (Debian 14
 0010 2e322e30 2d362920 31342e32 2e3000    .2.0-6) 14.2.0. 
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 1a000000 00410e10 8602430d  .........A....C.
 0030 06550c07 08000000                    .U......

你提供的 objdump -d hello.o 命令输出显示了 hello.o 对象文件中 .text 节的反汇编代码。以下是对这段代码的逐行解释:

  1. 0000000000000000 <main>:

    • 这是函数 main 的开始,地址为 0x0000000000000000
  2. 0: 55 push %rbp

    • 将基指针寄存器 rbp 的值压入栈中,这是函数调用的常规操作,用于保存旧的基指针。
  3. 1: 48 89 e5 mov %rsp,%rbp

    • 将栈指针寄存器 rsp 的值移动到基指针寄存器 rbp 中,设置新的基指针。
  4. 4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax

    • 将指令指针寄存器 rip 相对的地址(这里是当前指令的地址加上0,即当前地址)加载到 rax 寄存器中。这里可能是一个错误,因为 lea 指令通常用于加载有效的内存地址。
  5. b: 48 89 c7 mov %rax,%rdi

    • rax 寄存器的值移动到第一个参数寄存器 rdi 中,准备调用函数。
  6. e: e8 00 00 00 00 call 13 <main+0x13>

    • 调用地址 0x13 处的函数。由于这是一个相对跳转,实际的调用地址是 0x13 加上当前 rip 的值。
  7. 13: b8 00 00 00 00 mov $0x0,%eax

    • 将立即数 0 移动到 eax 寄存器中,这通常是函数返回值的寄存器。
  8. 18: 5d pop %rbp

    • 从栈中弹出值到 rbp 寄存器,恢复旧的基指针。
  9. 19: c3 ret

    • 返回到调用 main 函数的地方。

从反汇编代码来看,这个 main 函数似乎调用了一个函数(可能是 puts,因为之前在重定位记录中看到了对 puts 的引用),然后返回 0。但是,lea 指令中的地址 0x0 可能是一个占位符,实际的地址将在链接时解析。这个函数没有做任何实质性的工作,只是调用了一个函数并返回 0。这可能是一个简单的示例程序,用于演示函数调用和返回。

objdump -s hello.o 输出(节内容)

这部分输出显示了 hello.o 文件中不同节的内容,以十六进制形式表示。

  1. .text 节内容

    0000  554889e5 488d0500 00000048 89c7e800  UH..H......H....
    0010  000000b8 00000000 5dc3           ........].      
    
    • 这些是 .text 节的机器代码指令,与 -d 选项的反汇编输出相对应。
  2. .rodata 节内容

    0000  68656c6c 6f2c2077 6f726c64 00        hello, world.   
    
    • 这是只读数据节,通常包含程序中的字符串常量。这里包含了字符串 “hello, world.”。
  3. .comment 节内容

    0000  00474343 3a202844 65626961 6e203134  .GCC: (Debian 14
    0010  2e322e30 2d362920 31342e32 2e3000    .2.0-6) 14.2.0. 
    
    • 这是注释节,包含了编译器的版本信息。这里显示的是 GCC 编译器的版本信息,表明这个文件是用 Debian 14.2.0-6 版本的 GCC 编译的。
  4. .eh_frame 节内容

    0000  14000000 00000000 017a5200 01781001  .........zR..x..
    0010  1b0c0708 90010000 1c000000 1c000000  ................
    0020  00000000 1a000000 00410e10 8602430d  .........A....C.
    0030  06550c07 08000000                    .U......
    
    • 这是异常处理帧节,包含了用于异常处理和栈展开的信息。这些数据对于运行时库中的异常处理机制是必要的。

这些输出提供了对象文件的详细视图,包括代码、数据和元数据。如果你有任何具体问题或需要进一步的解释,请随时提问。

四,代码段

Contents of section .comment:
Contents of section .data:
Contents of section .got:
Contents of section .dynamic:
Contents of section .fini_array:
Contents of section .eh_frame:
Contents of section .eh_frame_hdr:
Contents of section .fini:
Contents of section .rodata:
Contents of section .text:
Contents of section .plt.got:
Contents of section .plt.sec:
Contents of section .init:
Contents of section .plt:
Contents of section .dynstr:
Contents of section .dynsym:

你列出了一系列的ELF文件节(sections),这些节在可执行文件、可重定位文件和共享库中扮演着不同的角色。下面是每个节的简要说明:

  1. .comment

    • 包含文件的版本信息和编译器信息,通常用于调试和版本跟踪。
  2. .data

    • 包含已初始化的全局变量和静态变量。
  3. .got(Global Offset Table):

    • 用于动态链接的程序,存储全局变量和函数地址的引用。
  4. .dynamic

    • 包含动态链接信息,用于动态加载和链接共享库。
  5. .fini_array

    • 包含终止时(程序退出时)需要调用的函数指针数组。
  6. .eh_frame

    • 包含异常处理信息,用于C++异常和非局部跳转。
  7. .eh_frame_hdr

    • 包含异常处理帧头部信息,用于解析 .eh_frame 节。
  8. .fini

    • 包含程序终止时需要执行的代码,通常用于关闭资源和清理。
  9. .rodata(Read-Only Data):

    • 包含只读数据,如字符串常量。
  10. .text

    • 包含程序的执行代码。
  11. .plt.got

    • 特定于某些架构(如ARM),用于处理PLT(过程链接表)中的全局偏移表。
  12. .plt.sec

    • 特定于某些架构,与 .plt 节相关。
  13. .init

    • 包含程序启动时需要执行的代码,用于初始化。
  14. .plt(Procedure Linkage Table):

    • 包含用于动态链接的代码,用于解析外部函数调用。
  15. .dynstr

    • 包含动态链接中使用的字符串表,如符号名称。
  16. .dynsym(Dynamic Symbol Table):

    • 包含动态链接中使用的符号表,用于符号解析。

这些节是ELF文件格式的一部分,它们在程序的生命周期中(如加载、执行、终止)起着关键作用。每个节都有特定的目的和用途,对于理解程序的结构和行为至关重要。

;