c 语言学习笔记十二

ELF 文件


三种格式:
 
1 可重定位的目标文件


   可用readelf工具读取 
    readelf -a 文件名


ELF header
program header table


section header table




目标文件的布局 


      起始文件地址 Section或Header 
      0            ELF Header 
      0x34         .text 
      0x60         .data 
      0x98         .bss (此段为空) 
      0x98         .shstrtab 
      0xc8         Section Header Table 
      0x208        .symtab
      0x288        .strtab 
      0x2b0        .rel.text 
 2 可执行文件
 3 共享库




函数调用
 
  示例代码:
   int bar(int c,int d){
  int e=c+d;
reutrn e;
   }
   int foo(int a,int b){
  return bar(a,b);
   }
   int main(void){
  foo(2,3);
    return 0;
   }


  编译:gcc test.c -g (添加-g选项,在反汇编时可以把c代码和汇编代码穿插显示)
  反汇编:objdump -dS test
    示例代码如下:080483b4 <bar>:
 //将foo函数的ebp压栈,
 80483b4: 55                   push   %ebp
 //给epb赋新值指向bar 函数的栈底,
 80483b5: 89 e5                 mov    %esp,%ebp
 80483b7: 83 ec 10             sub    $0x10,%esp
 //访问两个参数
 80483ba: 8b 45 0c             mov    0xc(%ebp),%eax
 80483bd: 8b 55 08             mov    0x8(%ebp),%edx
 80483c0: 8d 04 02             lea    (%edx,%eax,1),%eax
 80483c3: 89 45 fc             mov    %eax,-0x4(%ebp)
 //把e的值读到eax寄存器中,
 80483c6: 8b 45 fc             mov    -0x4(%ebp),%eax
 //push   %ebp和mov    %esp,%ebp的逆操作,把ebp的值赋值给esp,
 80483c9: c9                   leave  
 //call指令的逆操作,
 80483ca: c3                   ret    


080483cb <foo>:
 //先将epb寄存器的值压栈,esp的值-4送给ebp,(esp指向栈顶,ebp指向栈底)
 80483cb: 55                   push   %ebp
 80483cc: 89 e5                 mov    %esp,%ebp
 80483ce: 83 ec 08             sub    $0x8,%esp
 80483d1: 8b 45 0c             mov    0xc(%ebp),%eax
 80483d4: 89 44 24 04           mov    %eax,0x4(%esp)
 80483d8: 8b 45 08             mov    0x8(%ebp),%eax
 80483db: 89 04 24             mov    %eax,(%esp)
 //把返回地址压栈调用bar函数
 80483de: e8 d1 ff ff ff       call   80483b4 <bar>
 80483e3: c9                   leave  
 80483e4: c3                   ret    


080483e5 <main>:
 80483e5: 55                   push   %ebp
 80483e6: 89 e5                 mov    %esp,%ebp
 80483e8: 83 ec 08             sub    $0x8,%esp
  //foo(2,3); 参数是从右向左依次压栈
 80483eb: c7 44 24 04 03 00 00 movl   $0x3,0x4(%esp)
 80483f2: 00 
 80483f3: c7 04 24 02 00 00 00 movl   $0x2,(%esp)
  //调用call指令:
  //        1 把call的下一条指令 0x80483ff 压栈,同时esp-4,现值为
  //        2 修改程序计数器eip,跳转到foo函数的开头执行 (80483cb <foo>)
 80483fa: e8 cc ff ff ff       call   80483cb <foo>
 80483ff: b8 00 00 00 00       mov    $0x0,%eax
 8048404: c9                   leave  
 8048405: c3                   ret    
 8048406: 90                   nop
 8048407: 90                   nop
 8048408: 90                   nop
 8048409: 90                   nop
 804840a: 90                   nop
 804840b: 90                   nop
 804840c: 90                   nop
 804840d: 90                   nop
 804840e: 90                   nop
 804840f: 90                   nop




main函数和启动例程


汇编程序的入口是_start 
 汇编的链接步骤是:
    as hello.s -o hello.o
    ld hello.o -o hello




c程序的入口是main()
 c程序的编译:(-o 给文件重新命名,-v查看编译过程)
    gcc -s test.c //生成汇编代码
    gcc -c test.s //生成目标文件
    gcc test.o //生成可执行文件
 
 readelf/nm命令查看.o文件








变量的存储布局


  示例代码: 
 #include<stdio.h>


/*全局变量*/
const int A=10;
int a=20;
static int b=30;
int c;


int main(void){
   /*局部变量*/
   static int a=40;
   char b[]="Hello World";
   register int c=50;
 
  printf("Hello World %d\n",c)
  return 0;
}
 
   编译: gcc test.c -g
   查看符号表:readelf -a a.out
    //local 局部变量
    49: 0804a01c     4 OBJECT  LOCAL  DEFAULT   24 b
    50: 0804a020     4 OBJECT  LOCAL  DEFAULT   24 a.1709
    //global全局变量
    69: 08048570     4 OBJECT  GLOBAL DEFAULT   15 A
    73: 0804a02c     4 OBJECT  GLOBAL DEFAULT   25 c
    74: 0804a018     4 OBJECT  GLOBAL DEFAULT   24 a










   示例代码如下:
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk 


Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   


0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   


0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   


0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   


0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   


0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000060 10   A  6   


1  4
  [ 6] .dynstr           STRTAB          0804822c 00022c 000067 00   A  0   


0  1
  [ 7] .gnu.version      VERSYM          08048294 000294 00000c 02   A  5   


0  2
  [ 8] .gnu.version_r    VERNEED         080482a0 0002a0 000030 00   A  6   


1  4
  [ 9] .rel.dyn          REL             080482d0 0002d0 000008 08   A  5   


0  4
  [10] .rel.plt          REL             080482d8 0002d8 000020 08   A  5  


12  4
  [11] .init             PROGBITS        080482f8 0002f8 00002e 00  AX  0   


0  4
  [12] .plt              PROGBITS        08048330 000330 000050 04  AX  0   


0 16
  [13] .text             PROGBITS        08048380 000380 0001cc 00  AX  0   


0 16
  [14] .fini             PROGBITS        0804854c 00054c 00001a 00  AX  0   


0  4
  //
  [15] .rodata           PROGBITS        08048568 000568 00001c 00   A  0   


0  4
  [16] .eh_frame_hdr     PROGBITS        08048584 000584 00002c 00   A  0   


0  4
  [17] .eh_frame         PROGBITS        080485b0 0005b0 0000a4 00   A  0   


0  4
  [18] .ctors            PROGBITS        08049f14 000f14 000008 00  WA  0   


0  4
  [19] .dtors            PROGBITS        08049f1c 000f1c 000008 00  WA  0   


0  4
  [20] .jcr              PROGBITS        08049f24 000f24 000004 00  WA  0   


0  4
  [21] .dynamic          DYNAMIC         08049f28 000f28 0000c8 08  WA  6   


0  4
  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   


0  4
  [23] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   


0  4
  [24] .data             PROGBITS        0804a010 001010 000014 00  WA  0   


0  4
  [25] .bss              NOBITS          0804a024 001024 00000c 00  WA  0   


0  4
  [26] .comment          PROGBITS        00000000 001024 000055 01  MS  0   


0  1
  [27] .debug_aranges    PROGBITS        00000000 001079 000020 00      0   


0  1
  [28] .debug_pubnames   PROGBITS        00000000 001099 00002d 00      0   


0  1
  [29] .debug_info       PROGBITS        00000000 0010c6 00010e 00      0   


0  1
  [30] .debug_abbrev     PROGBITS        00000000 0011d4 000085 00      0   


0  1
  [31] .debug_line       PROGBITS        00000000 001259 00003e 00      0   


0  1
  [32] .debug_frame      PROGBITS        00000000 001298 000038 00      0   


0  4
  [33] .debug_str        PROGBITS        00000000 0012d0 000076 01  MS  0   


0  1
  [34] .debug_loc        PROGBITS        00000000 001346 00002c 00      0   


0  1
  [35] .shstrtab         STRTAB          00000000 001372 000164 00      0   


0  1
  [36] .symtab           SYMTAB          00000000 001ac8 0004f0 10     37  


55  4
  [37] .strtab           STRTAB          00000000 001fb8 000229 00      0  








查看内容:hexdump -c a.out
示例代码如下:
0000560   � 203   �  \b   [   �  \0  \0 003  \0  \0  \0 001  \0 002  \0
0000570  \n  \0  \0  \0   H   e   l   l   o       W   o   r   l




c 语言的作用域:
 函数作用域: function scope 整个函数中有效
 文件作用域: file scope     文件的开始到末尾都有效
 块作用域:   block scope    {}之间有效
 函数原型作用域: function protorype scope 在函数原型内有效




同一命名空间的重名标示符:
  语名标号单独属于一个命名空间
  struct/enum/union属于一个命名空间
  其他标识符为一命名空间,宏定义覆盖所有,内层作用域覆盖处层作用域


标识符的链接属性:
  外部链接:external linkage 多个文件中声明多次也都代表同一标识符
  内部链接:internal linkage 某个文件中声明多次也都代表同一标识符
  无链接:no linkage 




存储类修饰符:
 static 静态分配,内部链接
 auto   自动在栈上分配空间,返回时自动释放,不能作用文件作用域
 register 分配专问寄存器存储,如果分配不开,则作为auto处理,不能作用文件作用



 extern 
 typedef




变量的生命周期:
  静态生存期: 内部外部链接,static ,直到程序结束
  自动生存期: 无链接,块作用域,退出块作用域时释放
  动态分配生存期:malloc函数在堆空间中分配内存,调用free释放内存

你可能感兴趣的:(c 语言学习笔记十二)