二.
1.预处理(preprocessing)->编译(compilation)->汇编(assembly)->链接(linking)
2.预编译 gcc -E hello.c -o hello.i
Hello.i中的内容:
# 1 "Hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "Hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 313 "/usr/include/features.h" 3 4
# 1 "/usr/include/bits/predefs.h" 1 3 4
# 314 "/usr/include/features.h" 2 3 4
# 346 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 353 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 354 "/usr/include/sys/cdefs.h" 2 3 4
# 347 "/usr/include/features.h" 2 3 4
# 378 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 5 "/usr/include/gnu/stubs.h" 2 3 4
# 1 "/usr/include/gnu/stubs-32.h" 1 3 4
# 8 "/usr/include/gnu/stubs.h" 2 3 4
# 379 "/usr/include/features.h" 2 3 4
# 29 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 1 3 4
# 211 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 3 4
typedef unsigned int size_t;
# 35 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/bits/types.h" 1 3 4
# 28 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 29 "/usr/include/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;
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
__extension__ typedef long long int __quad_t;
__extension__ typedef unsigned long long int __u_quad_t;
# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4
__extension__ typedef __u_quad_t __dev_t;
__extension__ typedef unsigned int __uid_t;
__extension__ typedef unsigned int __gid_t;
__extension__ typedef unsigned long int __ino_t;
__extension__ typedef __u_quad_t __ino64_t;
__extension__ typedef unsigned int __mode_t;
__extension__ typedef unsigned int __nlink_t;
__extension__ typedef long int __off_t;
__extension__ typedef __quad_t __off64_t;
__extension__ typedef int __pid_t;
__extension__ typedef struct { int __val[2]; } __fsid_t;
__extension__ typedef long int __clock_t;
__extension__ typedef unsigned long int __rlim_t;
__extension__ typedef __u_quad_t __rlim64_t;
__extension__ typedef unsigned int __id_t;
__extension__ typedef long int __time_t;
__extension__ typedef unsigned int __useconds_t;
__extension__ typedef long int __suseconds_t;
__extension__ typedef int __daddr_t;
__extension__ typedef long int __swblk_t;
__extension__ typedef int __key_t;
__extension__ typedef int __clockid_t;
__extension__ typedef void * __timer_t;
__extension__ typedef long int __blksize_t;
__extension__ typedef long int __blkcnt_t;
__extension__ typedef __quad_t __blkcnt64_t;
__extension__ typedef unsigned long int __fsblkcnt_t;
__extension__ typedef __u_quad_t __fsblkcnt64_t;
__extension__ typedef unsigned long int __fsfilcnt_t;
__extension__ typedef __u_quad_t __fsfilcnt64_t;
__extension__ typedef int __ssize_t;
typedef __off64_t __loff_t;
typedef __quad_t *__qaddr_t;
typedef char *__caddr_t;
__extension__ typedef int __intptr_t;
__extension__ typedef unsigned int __socklen_t;
# 37 "/usr/include/stdio.h" 2 3 4
# 45 "/usr/include/stdio.h" 3 4
struct _IO_FILE;
typedef struct _IO_FILE FILE;
# 65 "/usr/include/stdio.h" 3 4
typedef struct _IO_FILE __FILE;
# 75 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/libio.h" 1 3 4
# 32 "/usr/include/libio.h" 3 4
# 1 "/usr/include/_G_config.h" 1 3 4
# 15 "/usr/include/_G_config.h" 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 1 3 4
# 16 "/usr/include/_G_config.h" 2 3 4
# 1 "/usr/include/wchar.h" 1 3 4
# 83 "/usr/include/wchar.h" 3 4
typedef struct
{
int __count;
union
{
unsigned int __wch;
char __wchb[4];
} __value;
} __mbstate_t;
# 21 "/usr/include/_G_config.h" 2 3 4
typedef struct
{
__off_t __pos;
__mbstate_t __state;
} _G_fpos_t;
typedef struct
{
__off64_t __pos;
__mbstate_t __state;
} _G_fpos64_t;
# 53 "/usr/include/_G_config.h" 3 4
typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));
typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));
typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));
typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));
# 33 "/usr/include/libio.h" 2 3 4
# 53 "/usr/include/libio.h" 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h" 1 3 4
# 40 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 54 "/usr/include/libio.h" 2 3 4
# 170 "/usr/include/libio.h" 3 4
struct _IO_jump_t; struct _IO_FILE;
# 180 "/usr/include/libio.h" 3 4
typedef void _IO_lock_t;
struct _IO_marker {
struct _IO_marker *_next;
struct _IO_FILE *_sbuf;
int _pos;
# 203 "/usr/include/libio.h" 3 4
};
enum __codecvt_result
{
__codecvt_ok,
__codecvt_partial,
__codecvt_error,
__codecvt_noconv
};
# 271 "/usr/include/libio.h" 3 4
struct _IO_FILE {
int _flags;
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_buf_base;
char* _IO_buf_end;
char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _flags2;
__off_t _old_offset;
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
_IO_lock_t *_lock;
# 319 "/usr/include/libio.h" 3 4
__off64_t _offset;
# 328 "/usr/include/libio.h" 3 4
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;
int _mode;
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};
typedef struct _IO_FILE _IO_FILE;
struct _IO_FILE_plus;
extern struct _IO_FILE_plus _IO_2_1_stdin_;
extern struct _IO_FILE_plus _IO_2_1_stdout_;
extern struct _IO_FILE_plus _IO_2_1_stderr_;
# 364 "/usr/include/libio.h" 3 4
typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);
typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf,
size_t __n);
typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);
typedef int __io_close_fn (void *__cookie);
# 416 "/usr/include/libio.h" 3 4
extern int __underflow (_IO_FILE *);
extern int __uflow (_IO_FILE *);
extern int __overflow (_IO_FILE *, int);
# 460 "/usr/include/libio.h" 3 4
extern int _IO_getc (_IO_FILE *__fp);
extern int _IO_putc (int __c, _IO_FILE *__fp);
extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__));
extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__));
extern int _IO_peekc_locked (_IO_FILE *__fp);
extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__));
extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__));
extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__));
# 490 "/usr/include/libio.h" 3 4
extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
__gnuc_va_list, int *__restrict);
extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
__gnuc_va_list);
extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);
extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);
extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);
extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);
extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__));
# 76 "/usr/include/stdio.h" 2 3 4
# 89 "/usr/include/stdio.h" 3 4
typedef _G_fpos_t fpos_t;
# 141 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/bits/stdio_lim.h" 1 3 4
# 142 "/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__));
extern int rename (__const char *__old, __const char *__new) __attribute__ ((__nothrow__));
extern int renameat (int __oldfd, __const char *__old, int __newfd,
__const char *__new) __attribute__ ((__nothrow__));
extern FILE *tmpfile (void) ;
# 186 "/usr/include/stdio.h" 3 4
extern char *tmpnam (char *__s) __attribute__ ((__nothrow__)) ;
extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__)) ;
# 204 "/usr/include/stdio.h" 3 4
extern char *tempnam (__const char *__dir, __const char *__pfx)
__attribute__ ((__nothrow__)) __attribute__ ((__malloc__)) ;
extern int fclose (FILE *__stream);
extern int fflush (FILE *__stream);
# 229 "/usr/include/stdio.h" 3 4
extern int fflush_unlocked (FILE *__stream);
# 243 "/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) ;
# 272 "/usr/include/stdio.h" 3 4
# 283 "/usr/include/stdio.h" 3 4
extern FILE *fdopen (int __fd, __const char *__modes) __attribute__ ((__nothrow__)) ;
# 296 "/usr/include/stdio.h" 3 4
extern FILE *fmemopen (void *__s, size_t __len, __const char *__modes)
__attribute__ ((__nothrow__)) ;
extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__)) ;
extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__));
extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
int __modes, size_t __n) __attribute__ ((__nothrow__));
extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
size_t __size) __attribute__ ((__nothrow__));
extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__));
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)));
# 394 "/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__));
# 425 "/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__));
# 445 "/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__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
# 476 "/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__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
# 504 "/usr/include/stdio.h" 3 4
extern int fgetc (FILE *__stream);
extern int getc (FILE *__stream);
extern int getchar (void);
# 532 "/usr/include/stdio.h" 3 4
extern int getc_unlocked (FILE *__stream);
extern int getchar_unlocked (void);
# 543 "/usr/include/stdio.h" 3 4
extern int fgetc_unlocked (FILE *__stream);
extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream);
extern int putchar (int __c);
# 576 "/usr/include/stdio.h" 3 4
extern int fputc_unlocked (int __c, FILE *__stream);
extern int putc_unlocked (int __c, FILE *__stream);
extern int putchar_unlocked (int __c);
extern int getw (FILE *__stream);
extern int putw (int __w, FILE *__stream);
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
;
extern char *gets (char *__s) ;
# 638 "/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);
# 710 "/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);
# 746 "/usr/include/stdio.h" 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence);
extern __off_t ftello (FILE *__stream) ;
# 765 "/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);
# 788 "/usr/include/stdio.h" 3 4
# 797 "/usr/include/stdio.h" 3 4
extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__));
extern int feof (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int ferror (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__));
extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void perror (__const char *__s);
# 1 "/usr/include/bits/sys_errlist.h" 1 3 4
# 27 "/usr/include/bits/sys_errlist.h" 3 4
extern int sys_nerr;
extern __const char *__const sys_errlist[];
# 827 "/usr/include/stdio.h" 2 3 4
extern int fileno (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
# 846 "/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__));
# 886 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));
# 916 "/usr/include/stdio.h" 3 4
# 2 "Hello.c" 2
int main (int argc, char **argv)
{
printf("Hello World!\n");
return 0;
}
3.编译 gcc -S hello.i -o hello.s
Hello.s 中的内容:
.file "Hello.c"
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
4.汇编
gcc -c hello.s -o hello.o
或 as hello.s -o hello.o
5.链接
编译器:扫描->语法分析->语义分析->源代码优化->代码生成->目标代码优化
*【有限状态机】算法
* lex 词法分析器
语法分析器(Grammar Parser) ->产生语法树(Syntax Tree)就是以表达式为节点的树
*上下文无关语法(Context-free Grammar)
语法分析工具:yacc(Yet Another Compiler Compiler)
语义分析:
语义分析器(Semantic Analyzer)
静态语义
动态语义
中间语言生成:
源代码优化器(Source Code Optimizer)
中间代码可以将编译器分为 前端和 后端:
模块之间的通信:(1)函数调用(2)变量的访问
两者都可以归结为 模块间符号的引用
2.4 静态链接
ELF文件类型:可重定位文件,可执行文件,共享目标文件,核心转储文件
Relocatable File
Executable File
Shared Object File
Core Dump File
SimpleSection.c
int printf(const char* format, ...);
int global_init_var = 84;
int global_uninit_var;
void func1( int i )
{
printf("%d\n", i);
}
int main(void)
{
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1( static_var + static_var2 + a + b);
return a;
}
gcc -c SimpleSection.c
objdump -h SimpleSection.o 用来查看object内部的结构
* readelf 是专门针对ELF格式文件的解析器
* size命令可以用来查看ELF文件的代码段、数据段和BSS段的长度
ELF文件格式结构:
***
ELF Header
***
.text
***
.data
***
.bss
***
...other sections
***
Section header table
***
String Tables
Symbol Tables
....
整个链接过程正是基于符号来完成的
* nm 命令 可以用来查看*.o中的符号
$ nm SimpleSection.o
*函数签名(Function Signature)
*c++filt 可以用来解析被修饰过的名称
$ c++filt _ZN1N1C4funcEi
#ifdef __cplusplus
extern “C”{
#endif
void *memset (void *, int, size_t);
#ifdef __cplusplus
}
#endif
*弱符号 弱引用 强符号 强引用
如果一个程序被设计成可以支持单线程或多线程的模式,就可以通过弱引用的方法来判断当前的程序是链接到了单线程的Glibc库还是多线程的Glibc库(是否在编译时有-lpthread选项)
#include <stdio.h>
#include <pthread.h>
int pthread_create(
pthread_t *,
const pthread_attr_t*,
void * (*)(void*),
void *)
__attribute__ ((weak));
int main(){
if(pthread_create){
printf("This is multi-thread version\n");
// run the multi-thread version
// main_multi_thread()
}else{
printf("This is single-thread version\n");
}
}
$ gcc pthread.c -o pt
$ gcc pthread.c -lpthread -o pt
*在linux下我们可以用 strip 命令去掉调试信息!
四.静态链接
4.1 空间与地址分配
4.2符号解析与重定位
* objdump -d a.o 可以查看a.o的代码反汇编结果
* objdump -r a.o 可以查看a.o的重定位表
4.3COMMON块
4.4C++相关问题
*函数级别链接
4.5静态库链接
* ar -t libc.a ar工具查看静态库
e.g:
$ gcc -c -fno-builtin hello.c
//默认情况GCC会自作聪明的将”printf”替换成“puts”以提高运行速度
$ ar -x libc.a
//将libc.a 中的所有目标文件解压到当前目录
$ld hello.o printf.o
//链接却失败了!!!!!原因是缺少2个外部符号的定义
$ gcc -static --verbose -fno-builtin hello.c
--verbose 可以将编译链接的中间所有过程打印出来
cc1 GCC的c语言编译器
as GNU的汇编器
collect2 ld连接器的一个包装
4.6链接库控制
*.c
char * str = "Hello World!\n";
void print()
{
asm( "movl $13, %%edx \n\t"
"movl %0, %%ecx \n\t"
"movl $0, %%ebx \n\t"
"movl $4, %%eax \n\t"
"int $0x80 \n\t"
::"r"(str):"edx","ecx","ebx");
}
void exit()
{
asm("movl $42, %ebx \n\t"
"movl $1, %eax \n\t"
"int $0x80 \n\t");
}
void nomain()
{
print();
exit();
}
*.lds
ENTRY(nomain)
SECTIONS
{
. = 0x08048000 + SIZEOF_HEADERS;
tinytext : { *(.text) *(.data) *(.rodata)}
/DISCARD/ : {*(.comment)}
}
gcc -c -fno-builtin *.c
ld -static -T *.lds -o *.c *.o
4.7BFD库
本章小结
六.可执行文件的装载和执行
*页映射
6.3.1 进程的建立
(1)创建虚拟地址空间
(2)读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系
*虚拟内存区域 (VMA Virtual Memory Area)
(3)将CPU指令寄存器设置成可执行文件的入口,启动执行
段的权限:
(1)以代码段为代表的权限为可读可执行的段
(2)以数据段和BSS段为代表的权限为可读可写的段
(3)以只读数据段为代表的权限为只读的段
对于权限相同的段,我们可以合并映射(可以减少页面的碎片,节省内存空间)
从section角度看ELF文件就是链接视图(Linking View)
从segment的角度看ELF文件就是执行视图(Execution View)
fly@Baby-o_o:~/Code/HelloWorld$ readelf -S SectionMapping.elf
There are 27 section headers, starting at offset 0x7d84c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .note.ABI-tag NOTE 080480f4 0000f4 000020 00 A 0 0 4
[ 2] .note.gnu.build-i NOTE 08048114 000114 000024 00 A 0 0 4
[ 3] .init PROGBITS 08048138 000138 000030 00 AX 0 0 4
[ 4] .text PROGBITS 08048170 000170 05eb3c 00 AX 0 0 16
[ 5] __libc_freeres_fn PROGBITS 080a6cb0 05ecb0 000b57 00 AX 0 0 16
[ 6] .fini PROGBITS 080a7808 05f808 00001c 00 AX 0 0 4
[ 7] .rodata PROGBITS 080a7840 05f840 018650 00 A 0 0 32
[ 8] __libc_subfreeres PROGBITS 080bfe90 077e90 000030 00 A 0 0 4
[ 9] __libc_atexit PROGBITS 080bfec0 077ec0 000004 00 A 0 0 4
[10] .eh_frame PROGBITS 080bfec4 077ec4 004dc0 00 A 0 0 4
[11] .gcc_except_table PROGBITS 080c4c84 07cc84 00011a 00 A 0 0 1
[12] .tdata PROGBITS 080c5f98 07cf98 000010 00 WAT 0 0 4
[13] .tbss NOBITS 080c5fa8 07cfa8 000018 00 WAT 0 0 4
[14] .ctors PROGBITS 080c5fa8 07cfa8 000008 00 WA 0 0 4
[15] .dtors PROGBITS 080c5fb0 07cfb0 00000c 00 WA 0 0 4
[16] .jcr PROGBITS 080c5fbc 07cfbc 000004 00 WA 0 0 4
[17] .data.rel.ro PROGBITS 080c5fc0 07cfc0 00002c 00 WA 0 0 4
[18] .got PROGBITS 080c5fec 07cfec 000008 04 WA 0 0 4
[19] .got.plt PROGBITS 080c5ff4 07cff4 00000c 04 WA 0 0 4
[20] .data PROGBITS 080c6000 07d000 000720 00 WA 0 0 32
[21] .bss NOBITS 080c6720 07d720 001b5c 00 WA 0 0 32
[22] __libc_freeres_pt NOBITS 080c827c 07d720 000018 00 WA 0 0 4
[23] .comment PROGBITS 00000000 07d720 000023 01 MS 0 0 1
[24] .shstrtab STRTAB 00000000 07d743 000107 00 0 0 1
[25] .symtab SYMTAB 00000000 07dc84 008200 10 26 967 4
[26] .strtab STRTAB 00000000 085e84 007397 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
fly@Baby-o_o:~/Code/HelloWorld$ readelf -l SectionMapping.elf
Elf file type is EXEC (Executable file)
Entry point 0x8048170
There are 6 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x7cd9e 0x7cd9e R E 0x1000
LOAD 0x07cf98 0x080c5f98 0x080c5f98 0x00788 0x022fc RW 0x1000
NOTE 0x0000f4 0x080480f4 0x080480f4 0x00044 0x00044 R 0x4
TLS 0x07cf98 0x080c5f98 0x080c5f98 0x00010 0x00028 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x07cf98 0x080c5f98 0x080c5f98 0x00068 0x00068 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.build-id .init .text __libc_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit .eh_frame .gcc_except_table
01 .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs
02 .note.ABI-tag .note.gnu.build-id
03 .tdata .tbss
04
05 .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt
我们可以通过查看 “/proc”来查看进程的虚拟空间分布:
$ ./SectionMapping.elf &
[1]21963
$cat /proc/21963/maps
fly@Baby-o_o:~/Code/HelloWorld$ ./SectionMapping.elf &
[1] 3869
fly@Baby-o_o:~/Code/HelloWorld$ cat /proc/3869/maps
08048000-080c5000 r-xp 00000000 08:01 18874525 /home/fly/Code/HelloWorld/SectionMapping.elf
080c5000-080c7000 rwxp 0007c000 08:01 18874525 /home/fly/Code/HelloWorld/SectionMapping.elf
080c7000-080c9000 rwxp 00000000 00:00 0
08ee4000-08f06000 rwxp 00000000 00:00 0 [heap]
b7746000-b7747000 r-xp 00000000 00:00 0 [vdso]
bfc5b000-bfc70000 rw-p 00000000 00:00 0 [stack]
*匿名虚拟内存区域(Anonymous Virtual Memory Area)
p192
6.5 linux内核装载ELF过程简介
(1)用户层面:bash进程->fork()->execve()->执行elf->bash进程等待其结束
execve()被定义在unistd.h 原型:
int execve(const char *filename, char *const argv[], char *const envp[]);
*p174
七.动态链接
静态库的缺点:
(1)浪费内存空间,不同的程序调用相同的静态库,会在内存中存在两个相同的静态库的副本
(2)影响程序的更新、部署、和发布
一旦有一个模块需要更新,整个程序就要重新链接,发布给客户
为了解决上述静态库的缺点,动态库应运而生,把链接这个工程推迟到了运行时进行(动态链接 Dynamic Linking 的基本思想)
这样做的好处不仅仅是节省内存,还可以减少物理页面的换入换出,增加CPU缓存的命中率(因为不同进程间的数据和指令访问都集中在了同一个共享模块上)
缺点:当新旧模块接口不兼容的时候,导致原有的程序无法运行!!!
*延迟绑定
Example: SimpleDynamicalLinking
a.c
#include "Lib.h"
int main(){
foobar(1);
return 0;
}
b.c
#include "Lib.h"
int main(){
foobar(2);
return 0;
}
Lib.c
#include <stdio.h>
void foobar(int i){
printf("Printing from Lib.so %d\n", i);
}
Lib.h
#ifndef LIB_H
#define LIB_H
void foobar(int i);
#endif
$ gcc -fPIC -shared -o Lib.so Lib.c
$ gcc -o a a.c ./Lib.so
Libc -> [Compiler] -> Lib.o -> [Linker] <- [C Runtime Library]
|
\/
Lib.so
|
\/
a.c -> [Compiler] -> a.o -> [Linker] -> a
7.3 地址无关代码
静态库 使用编译时重定位
动态库 使用装载时重定位
如果上面只使用 -shared 参数, 则输出的共享对象 就是使用的 装载时重定位的方法
但是 这样虽然可以解决动态模块中有绝对地址引用,但是缺点是:指令部分无法在多个进程之间共享
这样就失去了动态链接节省内存的一大优势!!!
那么 -fPIC 参数有什么作用呢?
解决 共享对象指令中绝对地址重定位问题基本思路:
把指令中那些需要修改的部分分离出来,和数据部分放在一起,这样指令部分可以保持不变,而数据部分可以个在每个进程中拥有一个副本
这种方案目前被称为:地址无关代码(PIC, Position-independent Code)
共享对象模块中的地址引用按照是否为跨模块分为
(1)模块内部引用
(2)模块外部引用
按照引用方式:
(1)指令引用
(2)数据访问
于是我们得到4中情况:
(1)模块内部 的 函数调用、跳转。
(2)模块内部 的 数据访问,比如模块中定义的全局变量、静态变量。
(3)模块外部 的 函数调用、跳转。
(4)模块外部 的 数据访问,比如其他模块中定义的全局变量。
p217
1.预处理(preprocessing)->编译(compilation)->汇编(assembly)->链接(linking)
2.预编译 gcc -E hello.c -o hello.i
Hello.i中的内容:
# 1 "Hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "Hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 313 "/usr/include/features.h" 3 4
# 1 "/usr/include/bits/predefs.h" 1 3 4
# 314 "/usr/include/features.h" 2 3 4
# 346 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 353 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 354 "/usr/include/sys/cdefs.h" 2 3 4
# 347 "/usr/include/features.h" 2 3 4
# 378 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 5 "/usr/include/gnu/stubs.h" 2 3 4
# 1 "/usr/include/gnu/stubs-32.h" 1 3 4
# 8 "/usr/include/gnu/stubs.h" 2 3 4
# 379 "/usr/include/features.h" 2 3 4
# 29 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 1 3 4
# 211 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 3 4
typedef unsigned int size_t;
# 35 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/bits/types.h" 1 3 4
# 28 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 29 "/usr/include/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;
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
__extension__ typedef long long int __quad_t;
__extension__ typedef unsigned long long int __u_quad_t;
# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4
__extension__ typedef __u_quad_t __dev_t;
__extension__ typedef unsigned int __uid_t;
__extension__ typedef unsigned int __gid_t;
__extension__ typedef unsigned long int __ino_t;
__extension__ typedef __u_quad_t __ino64_t;
__extension__ typedef unsigned int __mode_t;
__extension__ typedef unsigned int __nlink_t;
__extension__ typedef long int __off_t;
__extension__ typedef __quad_t __off64_t;
__extension__ typedef int __pid_t;
__extension__ typedef struct { int __val[2]; } __fsid_t;
__extension__ typedef long int __clock_t;
__extension__ typedef unsigned long int __rlim_t;
__extension__ typedef __u_quad_t __rlim64_t;
__extension__ typedef unsigned int __id_t;
__extension__ typedef long int __time_t;
__extension__ typedef unsigned int __useconds_t;
__extension__ typedef long int __suseconds_t;
__extension__ typedef int __daddr_t;
__extension__ typedef long int __swblk_t;
__extension__ typedef int __key_t;
__extension__ typedef int __clockid_t;
__extension__ typedef void * __timer_t;
__extension__ typedef long int __blksize_t;
__extension__ typedef long int __blkcnt_t;
__extension__ typedef __quad_t __blkcnt64_t;
__extension__ typedef unsigned long int __fsblkcnt_t;
__extension__ typedef __u_quad_t __fsblkcnt64_t;
__extension__ typedef unsigned long int __fsfilcnt_t;
__extension__ typedef __u_quad_t __fsfilcnt64_t;
__extension__ typedef int __ssize_t;
typedef __off64_t __loff_t;
typedef __quad_t *__qaddr_t;
typedef char *__caddr_t;
__extension__ typedef int __intptr_t;
__extension__ typedef unsigned int __socklen_t;
# 37 "/usr/include/stdio.h" 2 3 4
# 45 "/usr/include/stdio.h" 3 4
struct _IO_FILE;
typedef struct _IO_FILE FILE;
# 65 "/usr/include/stdio.h" 3 4
typedef struct _IO_FILE __FILE;
# 75 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/libio.h" 1 3 4
# 32 "/usr/include/libio.h" 3 4
# 1 "/usr/include/_G_config.h" 1 3 4
# 15 "/usr/include/_G_config.h" 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h" 1 3 4
# 16 "/usr/include/_G_config.h" 2 3 4
# 1 "/usr/include/wchar.h" 1 3 4
# 83 "/usr/include/wchar.h" 3 4
typedef struct
{
int __count;
union
{
unsigned int __wch;
char __wchb[4];
} __value;
} __mbstate_t;
# 21 "/usr/include/_G_config.h" 2 3 4
typedef struct
{
__off_t __pos;
__mbstate_t __state;
} _G_fpos_t;
typedef struct
{
__off64_t __pos;
__mbstate_t __state;
} _G_fpos64_t;
# 53 "/usr/include/_G_config.h" 3 4
typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));
typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));
typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));
typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));
# 33 "/usr/include/libio.h" 2 3 4
# 53 "/usr/include/libio.h" 3 4
# 1 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h" 1 3 4
# 40 "/usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 54 "/usr/include/libio.h" 2 3 4
# 170 "/usr/include/libio.h" 3 4
struct _IO_jump_t; struct _IO_FILE;
# 180 "/usr/include/libio.h" 3 4
typedef void _IO_lock_t;
struct _IO_marker {
struct _IO_marker *_next;
struct _IO_FILE *_sbuf;
int _pos;
# 203 "/usr/include/libio.h" 3 4
};
enum __codecvt_result
{
__codecvt_ok,
__codecvt_partial,
__codecvt_error,
__codecvt_noconv
};
# 271 "/usr/include/libio.h" 3 4
struct _IO_FILE {
int _flags;
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_buf_base;
char* _IO_buf_end;
char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _flags2;
__off_t _old_offset;
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
_IO_lock_t *_lock;
# 319 "/usr/include/libio.h" 3 4
__off64_t _offset;
# 328 "/usr/include/libio.h" 3 4
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;
int _mode;
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};
typedef struct _IO_FILE _IO_FILE;
struct _IO_FILE_plus;
extern struct _IO_FILE_plus _IO_2_1_stdin_;
extern struct _IO_FILE_plus _IO_2_1_stdout_;
extern struct _IO_FILE_plus _IO_2_1_stderr_;
# 364 "/usr/include/libio.h" 3 4
typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);
typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf,
size_t __n);
typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);
typedef int __io_close_fn (void *__cookie);
# 416 "/usr/include/libio.h" 3 4
extern int __underflow (_IO_FILE *);
extern int __uflow (_IO_FILE *);
extern int __overflow (_IO_FILE *, int);
# 460 "/usr/include/libio.h" 3 4
extern int _IO_getc (_IO_FILE *__fp);
extern int _IO_putc (int __c, _IO_FILE *__fp);
extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__));
extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__));
extern int _IO_peekc_locked (_IO_FILE *__fp);
extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__));
extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__));
extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__));
# 490 "/usr/include/libio.h" 3 4
extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
__gnuc_va_list, int *__restrict);
extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
__gnuc_va_list);
extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);
extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);
extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);
extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);
extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__));
# 76 "/usr/include/stdio.h" 2 3 4
# 89 "/usr/include/stdio.h" 3 4
typedef _G_fpos_t fpos_t;
# 141 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/bits/stdio_lim.h" 1 3 4
# 142 "/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__));
extern int rename (__const char *__old, __const char *__new) __attribute__ ((__nothrow__));
extern int renameat (int __oldfd, __const char *__old, int __newfd,
__const char *__new) __attribute__ ((__nothrow__));
extern FILE *tmpfile (void) ;
# 186 "/usr/include/stdio.h" 3 4
extern char *tmpnam (char *__s) __attribute__ ((__nothrow__)) ;
extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__)) ;
# 204 "/usr/include/stdio.h" 3 4
extern char *tempnam (__const char *__dir, __const char *__pfx)
__attribute__ ((__nothrow__)) __attribute__ ((__malloc__)) ;
extern int fclose (FILE *__stream);
extern int fflush (FILE *__stream);
# 229 "/usr/include/stdio.h" 3 4
extern int fflush_unlocked (FILE *__stream);
# 243 "/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) ;
# 272 "/usr/include/stdio.h" 3 4
# 283 "/usr/include/stdio.h" 3 4
extern FILE *fdopen (int __fd, __const char *__modes) __attribute__ ((__nothrow__)) ;
# 296 "/usr/include/stdio.h" 3 4
extern FILE *fmemopen (void *__s, size_t __len, __const char *__modes)
__attribute__ ((__nothrow__)) ;
extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__)) ;
extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__));
extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
int __modes, size_t __n) __attribute__ ((__nothrow__));
extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
size_t __size) __attribute__ ((__nothrow__));
extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__));
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)));
# 394 "/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__));
# 425 "/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__));
# 445 "/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__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
# 476 "/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__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
# 504 "/usr/include/stdio.h" 3 4
extern int fgetc (FILE *__stream);
extern int getc (FILE *__stream);
extern int getchar (void);
# 532 "/usr/include/stdio.h" 3 4
extern int getc_unlocked (FILE *__stream);
extern int getchar_unlocked (void);
# 543 "/usr/include/stdio.h" 3 4
extern int fgetc_unlocked (FILE *__stream);
extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream);
extern int putchar (int __c);
# 576 "/usr/include/stdio.h" 3 4
extern int fputc_unlocked (int __c, FILE *__stream);
extern int putc_unlocked (int __c, FILE *__stream);
extern int putchar_unlocked (int __c);
extern int getw (FILE *__stream);
extern int putw (int __w, FILE *__stream);
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
;
extern char *gets (char *__s) ;
# 638 "/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);
# 710 "/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);
# 746 "/usr/include/stdio.h" 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence);
extern __off_t ftello (FILE *__stream) ;
# 765 "/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);
# 788 "/usr/include/stdio.h" 3 4
# 797 "/usr/include/stdio.h" 3 4
extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__));
extern int feof (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int ferror (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__));
extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void perror (__const char *__s);
# 1 "/usr/include/bits/sys_errlist.h" 1 3 4
# 27 "/usr/include/bits/sys_errlist.h" 3 4
extern int sys_nerr;
extern __const char *__const sys_errlist[];
# 827 "/usr/include/stdio.h" 2 3 4
extern int fileno (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
# 846 "/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__));
# 886 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));
# 916 "/usr/include/stdio.h" 3 4
# 2 "Hello.c" 2
int main (int argc, char **argv)
{
printf("Hello World!\n");
return 0;
}
3.编译 gcc -S hello.i -o hello.s
Hello.s 中的内容:
.file "Hello.c"
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
4.汇编
gcc -c hello.s -o hello.o
或 as hello.s -o hello.o
5.链接
编译器:扫描->语法分析->语义分析->源代码优化->代码生成->目标代码优化
*【有限状态机】算法
* lex 词法分析器
语法分析器(Grammar Parser) ->产生语法树(Syntax Tree)就是以表达式为节点的树
*上下文无关语法(Context-free Grammar)
语法分析工具:yacc(Yet Another Compiler Compiler)
语义分析:
语义分析器(Semantic Analyzer)
静态语义
动态语义
中间语言生成:
源代码优化器(Source Code Optimizer)
中间代码可以将编译器分为 前端和 后端:
模块之间的通信:(1)函数调用(2)变量的访问
两者都可以归结为 模块间符号的引用
2.4 静态链接
ELF文件类型:可重定位文件,可执行文件,共享目标文件,核心转储文件
Relocatable File
Executable File
Shared Object File
Core Dump File
SimpleSection.c
int printf(const char* format, ...);
int global_init_var = 84;
int global_uninit_var;
void func1( int i )
{
printf("%d\n", i);
}
int main(void)
{
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1( static_var + static_var2 + a + b);
return a;
}
gcc -c SimpleSection.c
objdump -h SimpleSection.o 用来查看object内部的结构
* readelf 是专门针对ELF格式文件的解析器
* size命令可以用来查看ELF文件的代码段、数据段和BSS段的长度
ELF文件格式结构:
***
ELF Header
***
.text
***
.data
***
.bss
***
...other sections
***
Section header table
***
String Tables
Symbol Tables
....
整个链接过程正是基于符号来完成的
* nm 命令 可以用来查看*.o中的符号
$ nm SimpleSection.o
*函数签名(Function Signature)
*c++filt 可以用来解析被修饰过的名称
$ c++filt _ZN1N1C4funcEi
#ifdef __cplusplus
extern “C”{
#endif
void *memset (void *, int, size_t);
#ifdef __cplusplus
}
#endif
*弱符号 弱引用 强符号 强引用
如果一个程序被设计成可以支持单线程或多线程的模式,就可以通过弱引用的方法来判断当前的程序是链接到了单线程的Glibc库还是多线程的Glibc库(是否在编译时有-lpthread选项)
#include <stdio.h>
#include <pthread.h>
int pthread_create(
pthread_t *,
const pthread_attr_t*,
void * (*)(void*),
void *)
__attribute__ ((weak));
int main(){
if(pthread_create){
printf("This is multi-thread version\n");
// run the multi-thread version
// main_multi_thread()
}else{
printf("This is single-thread version\n");
}
}
$ gcc pthread.c -o pt
$ gcc pthread.c -lpthread -o pt
*在linux下我们可以用 strip 命令去掉调试信息!
四.静态链接
4.1 空间与地址分配
4.2符号解析与重定位
* objdump -d a.o 可以查看a.o的代码反汇编结果
* objdump -r a.o 可以查看a.o的重定位表
4.3COMMON块
4.4C++相关问题
*函数级别链接
4.5静态库链接
* ar -t libc.a ar工具查看静态库
e.g:
$ gcc -c -fno-builtin hello.c
//默认情况GCC会自作聪明的将”printf”替换成“puts”以提高运行速度
$ ar -x libc.a
//将libc.a 中的所有目标文件解压到当前目录
$ld hello.o printf.o
//链接却失败了!!!!!原因是缺少2个外部符号的定义
$ gcc -static --verbose -fno-builtin hello.c
--verbose 可以将编译链接的中间所有过程打印出来
cc1 GCC的c语言编译器
as GNU的汇编器
collect2 ld连接器的一个包装
4.6链接库控制
*.c
char * str = "Hello World!\n";
void print()
{
asm( "movl $13, %%edx \n\t"
"movl %0, %%ecx \n\t"
"movl $0, %%ebx \n\t"
"movl $4, %%eax \n\t"
"int $0x80 \n\t"
::"r"(str):"edx","ecx","ebx");
}
void exit()
{
asm("movl $42, %ebx \n\t"
"movl $1, %eax \n\t"
"int $0x80 \n\t");
}
void nomain()
{
print();
exit();
}
*.lds
ENTRY(nomain)
SECTIONS
{
. = 0x08048000 + SIZEOF_HEADERS;
tinytext : { *(.text) *(.data) *(.rodata)}
/DISCARD/ : {*(.comment)}
}
gcc -c -fno-builtin *.c
ld -static -T *.lds -o *.c *.o
4.7BFD库
本章小结
六.可执行文件的装载和执行
*页映射
6.3.1 进程的建立
(1)创建虚拟地址空间
(2)读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系
*虚拟内存区域 (VMA Virtual Memory Area)
(3)将CPU指令寄存器设置成可执行文件的入口,启动执行
段的权限:
(1)以代码段为代表的权限为可读可执行的段
(2)以数据段和BSS段为代表的权限为可读可写的段
(3)以只读数据段为代表的权限为只读的段
对于权限相同的段,我们可以合并映射(可以减少页面的碎片,节省内存空间)
从section角度看ELF文件就是链接视图(Linking View)
从segment的角度看ELF文件就是执行视图(Execution View)
fly@Baby-o_o:~/Code/HelloWorld$ readelf -S SectionMapping.elf
There are 27 section headers, starting at offset 0x7d84c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .note.ABI-tag NOTE 080480f4 0000f4 000020 00 A 0 0 4
[ 2] .note.gnu.build-i NOTE 08048114 000114 000024 00 A 0 0 4
[ 3] .init PROGBITS 08048138 000138 000030 00 AX 0 0 4
[ 4] .text PROGBITS 08048170 000170 05eb3c 00 AX 0 0 16
[ 5] __libc_freeres_fn PROGBITS 080a6cb0 05ecb0 000b57 00 AX 0 0 16
[ 6] .fini PROGBITS 080a7808 05f808 00001c 00 AX 0 0 4
[ 7] .rodata PROGBITS 080a7840 05f840 018650 00 A 0 0 32
[ 8] __libc_subfreeres PROGBITS 080bfe90 077e90 000030 00 A 0 0 4
[ 9] __libc_atexit PROGBITS 080bfec0 077ec0 000004 00 A 0 0 4
[10] .eh_frame PROGBITS 080bfec4 077ec4 004dc0 00 A 0 0 4
[11] .gcc_except_table PROGBITS 080c4c84 07cc84 00011a 00 A 0 0 1
[12] .tdata PROGBITS 080c5f98 07cf98 000010 00 WAT 0 0 4
[13] .tbss NOBITS 080c5fa8 07cfa8 000018 00 WAT 0 0 4
[14] .ctors PROGBITS 080c5fa8 07cfa8 000008 00 WA 0 0 4
[15] .dtors PROGBITS 080c5fb0 07cfb0 00000c 00 WA 0 0 4
[16] .jcr PROGBITS 080c5fbc 07cfbc 000004 00 WA 0 0 4
[17] .data.rel.ro PROGBITS 080c5fc0 07cfc0 00002c 00 WA 0 0 4
[18] .got PROGBITS 080c5fec 07cfec 000008 04 WA 0 0 4
[19] .got.plt PROGBITS 080c5ff4 07cff4 00000c 04 WA 0 0 4
[20] .data PROGBITS 080c6000 07d000 000720 00 WA 0 0 32
[21] .bss NOBITS 080c6720 07d720 001b5c 00 WA 0 0 32
[22] __libc_freeres_pt NOBITS 080c827c 07d720 000018 00 WA 0 0 4
[23] .comment PROGBITS 00000000 07d720 000023 01 MS 0 0 1
[24] .shstrtab STRTAB 00000000 07d743 000107 00 0 0 1
[25] .symtab SYMTAB 00000000 07dc84 008200 10 26 967 4
[26] .strtab STRTAB 00000000 085e84 007397 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
fly@Baby-o_o:~/Code/HelloWorld$ readelf -l SectionMapping.elf
Elf file type is EXEC (Executable file)
Entry point 0x8048170
There are 6 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x7cd9e 0x7cd9e R E 0x1000
LOAD 0x07cf98 0x080c5f98 0x080c5f98 0x00788 0x022fc RW 0x1000
NOTE 0x0000f4 0x080480f4 0x080480f4 0x00044 0x00044 R 0x4
TLS 0x07cf98 0x080c5f98 0x080c5f98 0x00010 0x00028 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x07cf98 0x080c5f98 0x080c5f98 0x00068 0x00068 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.build-id .init .text __libc_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit .eh_frame .gcc_except_table
01 .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs
02 .note.ABI-tag .note.gnu.build-id
03 .tdata .tbss
04
05 .tdata .ctors .dtors .jcr .data.rel.ro .got .got.plt
我们可以通过查看 “/proc”来查看进程的虚拟空间分布:
$ ./SectionMapping.elf &
[1]21963
$cat /proc/21963/maps
fly@Baby-o_o:~/Code/HelloWorld$ ./SectionMapping.elf &
[1] 3869
fly@Baby-o_o:~/Code/HelloWorld$ cat /proc/3869/maps
08048000-080c5000 r-xp 00000000 08:01 18874525 /home/fly/Code/HelloWorld/SectionMapping.elf
080c5000-080c7000 rwxp 0007c000 08:01 18874525 /home/fly/Code/HelloWorld/SectionMapping.elf
080c7000-080c9000 rwxp 00000000 00:00 0
08ee4000-08f06000 rwxp 00000000 00:00 0 [heap]
b7746000-b7747000 r-xp 00000000 00:00 0 [vdso]
bfc5b000-bfc70000 rw-p 00000000 00:00 0 [stack]
*匿名虚拟内存区域(Anonymous Virtual Memory Area)
p192
6.5 linux内核装载ELF过程简介
(1)用户层面:bash进程->fork()->execve()->执行elf->bash进程等待其结束
execve()被定义在unistd.h 原型:
int execve(const char *filename, char *const argv[], char *const envp[]);
*p174
七.动态链接
静态库的缺点:
(1)浪费内存空间,不同的程序调用相同的静态库,会在内存中存在两个相同的静态库的副本
(2)影响程序的更新、部署、和发布
一旦有一个模块需要更新,整个程序就要重新链接,发布给客户
为了解决上述静态库的缺点,动态库应运而生,把链接这个工程推迟到了运行时进行(动态链接 Dynamic Linking 的基本思想)
这样做的好处不仅仅是节省内存,还可以减少物理页面的换入换出,增加CPU缓存的命中率(因为不同进程间的数据和指令访问都集中在了同一个共享模块上)
缺点:当新旧模块接口不兼容的时候,导致原有的程序无法运行!!!
*延迟绑定
Example: SimpleDynamicalLinking
a.c
#include "Lib.h"
int main(){
foobar(1);
return 0;
}
b.c
#include "Lib.h"
int main(){
foobar(2);
return 0;
}
Lib.c
#include <stdio.h>
void foobar(int i){
printf("Printing from Lib.so %d\n", i);
}
Lib.h
#ifndef LIB_H
#define LIB_H
void foobar(int i);
#endif
$ gcc -fPIC -shared -o Lib.so Lib.c
$ gcc -o a a.c ./Lib.so
Libc -> [Compiler] -> Lib.o -> [Linker] <- [C Runtime Library]
|
\/
Lib.so
|
\/
a.c -> [Compiler] -> a.o -> [Linker] -> a
7.3 地址无关代码
静态库 使用编译时重定位
动态库 使用装载时重定位
如果上面只使用 -shared 参数, 则输出的共享对象 就是使用的 装载时重定位的方法
但是 这样虽然可以解决动态模块中有绝对地址引用,但是缺点是:指令部分无法在多个进程之间共享
这样就失去了动态链接节省内存的一大优势!!!
那么 -fPIC 参数有什么作用呢?
解决 共享对象指令中绝对地址重定位问题基本思路:
把指令中那些需要修改的部分分离出来,和数据部分放在一起,这样指令部分可以保持不变,而数据部分可以个在每个进程中拥有一个副本
这种方案目前被称为:地址无关代码(PIC, Position-independent Code)
共享对象模块中的地址引用按照是否为跨模块分为
(1)模块内部引用
(2)模块外部引用
按照引用方式:
(1)指令引用
(2)数据访问
于是我们得到4中情况:
(1)模块内部 的 函数调用、跳转。
(2)模块内部 的 数据访问,比如模块中定义的全局变量、静态变量。
(3)模块外部 的 函数调用、跳转。
(4)模块外部 的 数据访问,比如其他模块中定义的全局变量。
p217
相关推荐
《程序员的自我修养--链接、装载与库》是一本深入探讨程序构建过程的书籍,它涵盖了从源代码到可执行文件的关键步骤。阅读笔记主要围绕以下几个核心知识点展开: 1. **编译与链接**: - **编译**是将高级语言转化...
读书笔记:程序员的自我修养——链接、装载与库
读书笔记:程序员的自我修养阅读笔记
读书笔记:程序员的自我修养笔记
读书笔记:程序员的自我修养——学习笔记
读书笔记:程序员的自我修养
读书笔记:程序员的自我修养springboot
读书笔记:程序员的自我修养实验
读书笔记:关于程序员的自我修养
读书笔记:专业程序员的自我修养
读书笔记:《程序员的自我修养》
读书笔记:一个程序员的自我修养
读书笔记:程序员的自我修养中的示例代码
读书笔记:《程序员的自我修养》学习
读书笔记:程序员的自我修养链接、装载与库
读书笔记:程序员的自我修养 链接、装载与库
读书笔记:程序员的自我修养装载、链接和库
读书笔记:《程序员的自我修养——链接、装载与库》读书笔记
读书笔记:程序员的自我修养最后一章实现的miniCRT
读书笔记:程序员的自我修养的源程序和Mini CRT