LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 9314|回复: 26

请问strip命令到底对可执行文件干了什么?

[复制链接]
发表于 2006-1-13 14:08:42 | 显示全部楼层 |阅读模式
strip
用法:strip <选项> 输入文件
从文件中删除符号和节

那么,删除符号和节之后对程序有什么影响呢(文件变小了,但是好像还是可以正确运行)。符号和节是什么东西呀?
发表于 2006-1-13 14:30:13 | 显示全部楼层
一起讨论一下吧,呵呵。我是用 a.out 格式来理解的。

下面是 UNIX 中 a.out 格式文件的布局:
  1. /*        Layout of a.out file :
  2. *
  3. *        header of 8 words        magic number 405, 407, 410, 411
  4. *                                text size        )
  5. *                                data size        ) in bytes but even
  6. *                                bss size        )
  7. *                                symbol table size
  8. *                                entry point
  9. *                                {unused}
  10. *                                flag set if no relocation
  11. *
  12. *
  13. *        header:                0
  14. *        text:                16
  15. *        data:                16+textsize
  16. *        relocation:        16+textsize+datasize
  17. *        symbol table:        16+2*(textsize+datasize) or 16+textsize+datasize
  18. *
  19. */
复制代码

下面是 a.out.h:
  1. struct        exec {        /* a.out header */
  2.         int             a_magic;        /* magic number */
  3.         unsigned        a_text;         /* size of text segment */
  4.         unsigned        a_data;         /* size of initialized data */
  5.         unsigned        a_bss;          /* size of unitialized data */
  6.         unsigned        a_syms;         /* size of symbol table */
  7.         unsigned        a_entry;         /* entry point */
  8.         unsigned        a_unused;        /* not used */
  9.         unsigned        a_flag;         /* relocation info stripped */
  10. };

  11. #define        A_MAGIC1        0407               /* normal */
  12. #define        A_MAGIC2        0410               /* read-only text */
  13. #define        A_MAGIC3        0411               /* separated I&D */
  14. #define        A_MAGIC4        0405               /* overlay */

  15. struct        nlist {        /* symbol table entry */
  16.         char            n_name[8];        /* symbol name */
  17.         int             n_type;            /* type flag */
  18.         unsigned        n_value;        /* value */
  19. };

  20.                 /* values for type flag */
  21. #define        N_UNDF        0        /* undefined */
  22. #define        N_ABS        01        /* absolute */
  23. #define        N_TEXT        02        /* text symbol */
  24. #define        N_DATA        03        /* data symbol */
  25. #define        N_BSS        04        /* bss symbol */
  26. #define        N_TYPE        037
  27. #define        N_REG        024        /* register name */
  28. #define        N_FN        037        /* file name symbol */
  29. #define        N_EXT        040        /* external bit, or'ed in */
  30. #define        FORMAT        "%06o"        /* to print a value */
复制代码

这是一个早期的 strip:
  1. #include <a.out.h>
  2. #include <signal.h>

  3. char        *tname;
  4. char        *mktemp();
  5. struct exec head;
  6. int         a_magic[] = {A_MAGIC1, A_MAGIC2, A_MAGIC3, A_MAGIC4, 0};
  7. int        status;
  8. int        tf;

  9. main(argc, argv)
  10. char *argv[];
  11. {
  12.         register i;

  13.         signal(SIGHUP, SIG_IGN);
  14.         signal(SIGINT, SIG_IGN);
  15.         signal(SIGQUIT, SIG_IGN);
  16.         tname = mktemp("/tmp/sXXXXX");
  17.         close(creat(tname, 0600));
  18.         tf = open(tname, 2);
  19.         if(tf < 0) {
  20.                 printf("cannot create temp file\n");
  21.                 exit(2);
  22.         }
  23.         for(i=1; i<argc; i++) {
  24.                 strip(argv[i]);
  25.                 if(status > 1)
  26.                         break;
  27.         }
  28.         close(tf);
  29.         unlink(tname);
  30.         exit(status);
  31. }

  32. strip(name)
  33. char *name;
  34. {
  35.         register f;
  36.         long size;
  37.         int i;

  38.         f = open(name, 0);
  39.         if(f < 0) {
  40.                 printf("cannot open %s\n", name);
  41.                 status = 1;
  42.                 goto out;
  43.         }
  44.         read(f, (char *)&head, sizeof(head));
  45.         for(i=0;a_magic[i];i++)
  46.                 if(a_magic[i] == head.a_magic) break;
  47.         if(a_magic[i] == 0) {
  48.                 printf("%s not in a.out format\n", name);
  49.                 status = 1;
  50.                 goto out;
  51.         }
  52.         if(head.a_syms == 0 && (head.a_flag&1) != 0) {
  53.                 printf("%s already stripped\n", name);
  54.                 goto out;
  55.         }
  56.         size = (long)head.a_text + head.a_data;
  57.         head.a_syms = 0;
  58.         head.a_flag |= 1;

  59.         lseek(tf, (long)0, 0);
  60.         write(tf, (char *)&head, sizeof(head));
  61.         if(copy(name, f, tf, size)) {
  62.                 status = 1;
  63.                 goto out;
  64.         }
  65.         size += sizeof(head);
  66.         close(f);
  67.         f = creat(name, 0666);
  68.         if(f < 0) {
  69.                 printf("%s cannot recreate\n", name);
  70.                 status = 1;
  71.                 goto out;
  72.         }
  73.         lseek(tf, (long)0, 0);
  74.         if(copy(name, tf, f, size))
  75.                 status = 2;

  76. out:
  77.         close(f);
  78. }

  79. copy(name, fr, to, size)
  80. char *name;
  81. long size;
  82. {
  83.         register s, n;
  84.         char buf[512];

  85.         while(size != 0) {
  86.                 s = 512;
  87.                 if(size < 512)
  88.                         s = size;
  89.                 n = read(fr, buf, s);
  90.                 if(n != s) {
  91.                         printf("%s unexpected eof\n", name);
  92.                         return(1);
  93.                 }
  94.                 n = write(to, buf, s);
  95.                 if(n != s) {
  96.                         printf("%s unexpected write eof\n", name);
  97.                         return(1);
  98.                 }
  99.                 size -= s;
  100.         }
  101.         return(0);
  102. }
复制代码

这就是 strip 的作用。
回复 支持 反对

使用道具 举报

发表于 2006-1-13 14:36:34 | 显示全部楼层
给个直观的吧,更详细的不是论坛可以说清楚的,你需要了解更多的ELF的东西。
  1. $cp /lib/libc.so.6 .
  2. $nm libc.so.6 | head
  3. 0024ea90 T a64l
  4. 00329fe0 r a64l_table
  5. 00242790 T abort
  6. 0033fce0 b abortfunc
  7. 00243e08 T abs
  8. 002e4460 W accept
  9. 002d4ba0 W access
  10. 002d4ba0 t __access
  11. 002dc3e0 T acct
  12. 002305d0 t add_alias
  13. $strip libc.so.6
  14. $nm libc.so.6
  15. nm: libc.so.6: no symbols
复制代码

这些symbol有什么用呢?用gdb调试跟踪的时候你就会知道了。
回复 支持 反对

使用道具 举报

发表于 2006-1-13 14:39:45 | 显示全部楼层
P.S:不赞成上面的用a.out格式来理解的方式,
ELF比a.out复杂多了。而且现在distro的内核不加入a.out的支持的,比如fedora的内核:
$cat /boot/config-2.6.14-1.1637_FC4 | grep AOUT
# CONFIG_BINFMT_AOUT is not set

还有
gcc产生的a.out文件和那个a.out格式只有历史关系,没有技术上的关联。
回复 支持 反对

使用道具 举报

发表于 2006-1-13 14:51:42 | 显示全部楼层
  1. NAME

  2.         a.out – assembler and link editor output

  3. SYNOPSIS

  4.         #include <a.out.h>

  5. DESCRIPTION

  6. A.out is the output file of the assembler as(1) and the link editor
  7. ld(1). Both programs make a.out executable if there were no errors and
  8. no unresolved external references. Layout information as given in the
  9. include file for the PDP11 is:

  10.         struct exec {        /* a.out header */
  11.                 short    a_magic;        /* magic number */
  12.                 unsigned a_text;        /* size of text segment */
  13.                 unsigned a_data;        /* size of initialized data */
  14.                 unsigned a_bss;                /* size of uninitialized data */
  15.                 unsigned a_syms;        /* size of symbol table */
  16.                 unsigned a_entry;        /* entry point */
  17.                 unsigned a_unused;        /* not used */
  18.                 unsigned a_flag;        /* relocation info stripped */
  19.         };
  20.         #define A_MAGIC1 0407                /* normal */
  21.         #define A_MAGIC2 0410                /* read-only text */
  22.         #define A_MAGIC3 0411                /* separated I&D */
  23.         #define A_MAGIC4 0405                /* overlay */
  24.         struct nlist {        /* symbol table entry */
  25.                 char     n_name[8];        /* symbol name */
  26.                 int      n_type;        /* type flag */
  27.                 unsigned n_value;        /* value */
  28.         };
  29.                 /* values for type flag */
  30.         #define N_UNDF 0                /* undefined */
  31.         #define N_ABS  01                /* absolute */
  32.         #define N_TEXT 02                /* text symbol */
  33.         #define N_DATA 03                /* data symbol */
  34.         #define N_BSS  04                /* bss symbol */
  35.         #define N_TYPE 037
  36.         #define N_REG  024                /* register name */
  37.         #define N_FN   037                /* file name symbol */
  38.         #define N_EXT  040                /* external bit, or’ed in */
  39.         #define FORMAT "%.6o"                /* to print a value */

  40. The file has four sections: a header, the program and data text,
  41. relocation information, and a symbol table (in that order). The last
  42. two may be empty if the program was loaded with the ‘– s’ option of ld
  43. or if the symbols and relocation have been removed by strip(1).

  44. In the header the sizes of each section are given in bytes, but are
  45. even. The size of the header is not included in any of the other
  46. sizes.

  47. When an a.out file is loaded into core for execution, three logical
  48. segments are set up: the text segment, the data segment (with
  49. uninitialized data, which starts off as all 0, following initialized),
  50. and a stack.  The text segment begins at 0 in the core image; the
  51. header is not loaded. If the magic number in the header is 0407(8), it
  52. indicates that the text segment is not to be write-protected and
  53. shared, so the data segment is immediately contiguous with the text
  54. segment. If the magic number is 0410, the data segment begins at the
  55. first 0 mod 8K byte boundary following the text segment, and the text
  56. segment is not writable by the program; if other processes are
  57. executing the same file, they will share the text segment.  If the
  58. magic number is 411, the text segment is again pure, write-protected,
  59. and shared, and moreover instruction and data space are separated; the
  60. text and data segment both begin at location 0. If the magic number is
  61. 0405, the text segment is overlaid on an existing (0411 or 0405) text
  62. segment and the existing data segment is preserved.

  63. The stack will occupy the highest possible locations in the core
  64. image: from 0177776(8) and growing downwards. The stack is
  65. automatically extended as required. The data segment is only extended
  66. as requested by brk(2).

  67. The start of the text segment in the file is 020(8); the start of the
  68. data segment is 020+St (the size of the text) the start of the
  69. relocation information is 020+St+Sd; the start of the symbol table is
  70. 020+2(St+Sd) if the relocation information is present, 020+St+Sd if
  71. not.

  72. The layout of a symbol table entry and the principal flag values that
  73. distinguish symbol types are given in the include file. Other flag
  74. values may occur if an assembly language program defines machine
  75. instructions.

  76. If a symbol’s type is undefined external, and the value field is
  77. non-zero, the symbol is interpreted by the loader ld as the name of a
  78. common region whose size is indicated by the value of the symbol.

  79. The value of a word in the text or data portions which is not a
  80. reference to an undefined external symbol is exactly that value which
  81. will appear in core when the file is executed. If a word in the text
  82. or data portion involves a reference to an undefined external symbol,
  83. as indicated by the relocation information for that word, then the
  84. value of the word as stored in the file is an offset from the
  85. associated external symbol. When the file is processed by the link
  86. editor and the external symbol becomes defined, the value of the
  87. symbol will be added into the word in the file.

  88. If relocation information is present, it amounts to one word per word
  89. of program text or initialized data.  There is no relocation
  90. information if the ‘relocation info stripped’ flag in the header is
  91. on.

  92. Bits 3-1 of a relocation word indicate the segment referred to by the
  93. text or data word associated with the relocation word:

  94. 000        absolute number
  95. 002        reference to text segment
  96. 004        reference to initialized data
  97. 006        reference to uninitialized data (bss)
  98. 010        reference to undefined external symbol

  99. Bit 0 of the relocation word indicates, if 1, that the reference is
  100. relative to the pc (e.g. ‘clr x’); if 0, that the reference is to the
  101. actual symbol (e.g., ‘clr *$x’).

  102. The remainder of the relocation word (bits 15-4) contains a symbol
  103. number in the case of external references, and is unused
  104. otherwise. The first symbol is numbered 0, the second 1, etc.

  105. SEE ALSO

  106.         as(1), ld(1), nm(1)
复制代码
回复 支持 反对

使用道具 举报

发表于 2006-1-13 14:52:44 | 显示全部楼层
我倒是觉得利用这些“老东西”来快速地理解原理是一种非常有效的方式
因为一个人阅读 gcc 和 binutils 的全部源代码几乎是不可能的,而早期的 cc、as、ld 这些程序的源代码是可以一个人读完的,并且尽管格式复杂了,原理还是一样的。
就好像相对论力学比牛顿力学复杂多了,从牛顿力学开始理解力学仍可认为是一个好的方式。
回复 支持 反对

使用道具 举报

发表于 2006-1-13 15:44:41 | 显示全部楼层
Post by herberteuler
我倒是觉得利用这些“老东西”来快速地理解原理是一种非常有效的方式
因为一个人阅读 gcc 和 binutils 的全部源代码几乎是不可能的,而早期的 cc、as、ld 这些程序的源代码是可以一个人读完的,并且尽管格式复杂了,原理还是一样的。
就好像相对论力学比牛顿力学复杂多了,从牛顿力学开始理解力学仍可认为是一个好的方式。


我倒是认为关于ELF的资料要比a.out的好找的多而且更为“实用",毕竟机器上都是ELF的东西,实验起来也方便。
回复 支持 反对

使用道具 举报

发表于 2006-1-13 16:09:18 | 显示全部楼层
Post by hellwolf
我倒是认为关于ELF的资料要比a.out的好找的多而且更为“实用",毕竟机器上都是ELF的东西,实验起来也方便。

呵呵,我手头有全套的早期 UNIX 的资料,从硬件手册,到操作系统,到编译器、汇编器、链接器。它们没有别的特点,就是小,小到可以在很短的时间内完全理解。

另一方面,有专门的模拟器可以作为实验工具。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-1-13 17:55:06 | 显示全部楼层
哦!就是说,那写Symbol就是主要是用来给GDB调试用的?

恩,还有一个问题就是,herberteuler给的那段代码中,创建文件的时候,用了0666,这是文件的权限吧?如果a.out创建为0666的话不是就不具有可执行权限了?

哦!时间不早了!先去考试了。
6:30的Linux操作系统,全校公选课,现在的中国,真是无语了,我看了课程的习题,其中最有印象的一道题就是:
用ls命令得到的结果中,可执行文件是用什么颜色显示的?

晕~~~~
回复 支持 反对

使用道具 举报

发表于 2006-1-13 18:06:18 | 显示全部楼层
Post by herberteuler
我倒是觉得利用这些“老东西”来快速地理解原理是一种非常有效的方式
因为一个人阅读 gcc 和 binutils 的全部源代码几乎是不可能的,而早期的 cc、as、ld 这些程序的源代码是可以一个人读完的,并且尽管格式复杂了,原理还是一样的。
就好像相对论力学比牛顿力学复杂多了,从牛顿力学开始理解力学仍可认为是一个好的方式。


相对论只是数学上复杂一些,概念绝对比牛顿简单多了
难道不是越接近真实的东西越简单才合理吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表