转自:http://blog.chinaunix.net/uid-10769062-id-3230811.html
Busybox-1.9.1 在util-linux/mount.c的line:1609行首先映入眼帘的是: int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 由于busybox是一个box,里面包含很多的可执行程序,如果cp,mount,umount等我们常用的一些命令,所以每个命令单独写入一个文件,而每个文件中也用类似mount_main()这样的命名方法作为局部的main函数。 MAIN_EXTERNALLY_VISIBLE的定义在 busybox-1.9.1/include/libbb.h中 如下: /* We need to export XXX_main from libbusybox * only if we build "individual" binaries */ #if ENABLE_FEATURE_INDIVIDUAL #define MAIN_EXTERNALLY_VISIBLE EXTERNALLY_VISIBLE #else #define MAIN_EXTERNALLY_VISIBLE #endif 而 EXTERNALLY_VISIBLE的定义在 busybox-1.9.1/include/platform.h中,line:73如下 /* -fwhole-program makes all symbols local. The attribute externally_visible forces a symbol global. */ # if __GNUC_PREREQ (4,1) # define EXTERNALLY_VISIBLE __attribute__(( visibility("default") )); //__attribute__ ((__externally_visible__)) # else # define EXTERNALLY_VISIBLE # endif /* GNUC >= 4.1 */ 其中,__GNUC_PREREQ() 是什么意思呢? 在 busybox-1.9.1/include/platform.h,line:10 /* Convenience macros to test the version of gcc. */ #undef __GNUC_PREREQ #if defined __GNUC__ && defined __GNUC_MINOR__ # define __GNUC_PREREQ(maj, min) ((__GNUC__ << 16) __GNUC_MINOR__ >= ((maj) << 16) (min)) #else # define __GNUC_PREREQ(maj, min) 0 #endif 首先取消 __GNUC_PREREQ原来的宏定义,然后再根据__GNUC__ 和__GNUC_MINOR__的情况重新定义 __GNUC_PREREQ。 #undef 是在后面取消以前定义的宏定义§ 其中, __GNUC__ 是gcc编译器编译代码时预定义的一个宏,他的值表示当前GCC的版本号,可以通过查看gcc版确定一下。 然后 __GNUC_MINOR__的含义也就可以推出了。 The macro contains the minor version number of the compiler. This can be used to work around differences between different releases of the compiler. It must always be used together with __GNUC__§. 返回去看 # if __GNUC_PREREQ (4,1) 其实就是看当前的GCC版本是否>=4.1然后再做下一步判断。 接下来的: #define EXTERNALLY_VISIBLE __attribute__(( visibility("default") )); 重点在于: __attribute__(( visibility("default") )); 通过这个链接:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html可知__attribute__ 的强大,可对变量,函数等symbols 对外的可见属性进行修改: visibility ("visibility_type") The visibility attribute on ELF targets causes the declaration to be emitted with default, hidden, protected or internal visibility. void __attribute__ ((visibility ("protected"))) f () { /* Do something. */; } int i __attribute__ ((visibility ("hidden"))); See the ELF gABI for complete details, but the short story is: default Default visibility is the normal case for ELF. This value is available for the visibility attribute to override other options that may change the assumed visibility of symbols. hidden Hidden visibility indicates that the symbol will not be placed into the dynamic symbol table, so no other module (executable or shared library) can reference it directly. internal Internal visibility is like hidden visibility, but with additional processor specific semantics. Unless otherwise specified by the psABI, GCC defines internal visibility to mean that the function is never called from another module. Note that hidden symbols, while they cannot be referenced directly by other modules, can be referenced indirectly via function pointers. By indicating that a symbol cannot be called from outside the module, GCC may for instance omit the load of a PIC register since it is known that the calling function loaded the correct value. protected Protected visibility indicates that the symbol will be placed in the dynamic symbol table, but that references within the defining module will bind to the local symbol. That is, the symbol cannot be overridden by another module. Not all ELF targets support this attribute. 接下来 /* parse long options, like --bind and --move. Note that -o option * and --option are synonymous. Yes, this means --remount,rw works. */ for (i = j = 0; i < argc; i ) { if (argv[i][0] == '-' && argv[i][1] == '-') { append_mount_options(&cmdopts, argv[i] 2); } else { argv[j ] = argv[i]; } } argv[j] = 0; argc = j; 主要目的是解析命令行中的参数和选项,针对的是带有 "- -" 类型的长选项,实际上,- - 和 - 是一样的。主要是通过 append_mount_options()这个函数完成,进入 append_mount_options()。 其中,cmdopts是一个指针,它通过 char *cmdopts = xstrdup(""), busybox-1.9.1/util-linux/mount.c line:170 /* Append mount options to string */ static void append_mount_options(char **oldopts, const char *newopts) { if (*oldopts && **oldopts) { /* do not insert options which are already there */ while (newopts[0]) { char *p; int len = strlen(newopts); p = strchr(newopts, ','); if (p) len = p - newopts; p = *oldopts; while (1) { if (!strncmp(p, newopts, len) && (p[len] == ',' || p[len] == '