KEIL ARM的帮助文件里对__main的描述:
程序的入口点在 C 库中的__main 处,在该点,库代码执行以下操作:
将非根运行区(只读和读写)从其载入地址复制到运行地址。同如果任何区被压缩,将它们从载入地址解压到运行地址。更多信息,请参阅链接器用户指南 。
清零 ZI 区域。
跳转到 __rt_entry。
如果不希望库执行这样的操作,可以如 例 2.1 中所示定义跳转到 __rt_entry的自有__main。
例 2.1. __main 和 __rt_entry
IMPORT __rt_entry
EXPORT __main
ENTRY
__main
B __rt_entry
END
库函数__rt_entry() 运行程序步骤如下:
调用 __rt_stackheap_init() 建立栈和堆。
调用 __rt_lib_init() 初始化引用的库函数、初始化语言环境 (locale),如果必要,还将为main()函数建立argc 和 argv。对于 C++,为任何顶级对象调用构造函数。
对于C++,为任何顶级对象调用构造函数作为 __cpp_initialize__aeabi_。更多信息,请参阅 C++ 初始化,建立和销毁 。
调用 main()函数 ———— 应用程序的用户级根。
从main()函数中,应用程序除了调用其他函数,还可调用库函数。有关详细信息,请参阅从 main()函数中调用库函数。从main()函数中调用库函数。
使用main()函数返回的值调用exit()。
/
从上面就可以看到__user_initial_stackheap的返回值到底是在哪里用到了,
就是“调用 __rt_stackheap_init() 建立栈和堆”这里,实际上还有其它的C库函数有用到,但肯定都是在__main之后,因为__main是C库函数的入口。
我说上面的代码没有调用__user_initial_stackheap,因为很明显,把STARTUP.S从头读到尾,根本没有调用__user_initial_stackheap的语句。那它在哪呢?“rt_misc.h”这个文件里有定义。
/*
* This can be defined to override the standard memory models' way
* of determining where to put the initial stack and heap.
*
* The input parameters R0 and R2 contain nothing useful. The input
* parameters SP and SL are the values that were in SP and SL when
* the program began execution (so you can return them if you want
* to keep that stack).
*
* The two `limit' fields in the return structure are ignored if
* you are using the one-region memory model: the memory region is
* taken to be all the space between heap_base and stack_base.
*/
struct __initial_stackheap {
unsigned heap_base; /* low-address end of initial heap */
unsigned stack_base; /* high-address end of initial stack */
unsigned heap_limit; /* high-address end of initial heap */
unsigned stack_limit; /* low-address end of initial stack */
};
extern __value_in_regs struct __initial_stackheap
__user_initial_stackheap(unsigned /*R0*/, unsigned /*SP*/,
unsigned /*R2*/, unsigned /*SL*/);
由于ARM应用的灵活性,可以通过分散加载文件来定义代码和变量的位置,所以堆栈的地址并不固定,这样,在ARM C库里的函数用到堆栈的地址时候,就用上面定义的变量来代替。
说它是不是多余,其实也不算,因为一般的STARTUP.S都只初始了栈,就是SP。没有初始堆,所以在这个函数里初始堆还是有必要的,而且这个函数的作用主要是返回堆栈的地址,这个地址除了初始化,还可以有其它的作用。毕竟我们不大方便在C语言里直接取SP的地址。
如果没有 B __mian 的话,就没有调用C库,也就用不到初始化C库。而不调用__main,直接进入main()当然是可以实现的,
程序的入口点在 C 库中的__main 处,在该点,库代码执行以下操作:
将非根运行区(只读和读写)从其载入地址复制到运行地址。同如果任何区被压缩,将它们从载入地址解压到运行地址。更多信息,请参阅链接器用户指南 。
清零 ZI 区域。
跳转到 __rt_entry。
如果不希望库执行这样的操作,可以如 例 2.1 中所示定义跳转到 __rt_entry的自有__main。
例 2.1. __main 和 __rt_entry
IMPORT __rt_entry
EXPORT __main
ENTRY
__main
B __rt_entry
END
库函数__rt_entry() 运行程序步骤如下:
调用 __rt_stackheap_init() 建立栈和堆。
调用 __rt_lib_init() 初始化引用的库函数、初始化语言环境 (locale),如果必要,还将为main()函数建立argc 和 argv。对于 C++,为任何顶级对象调用构造函数。
对于C++,为任何顶级对象调用构造函数作为 __cpp_initialize__aeabi_。更多信息,请参阅 C++ 初始化,建立和销毁 。
调用 main()函数 ———— 应用程序的用户级根。
从main()函数中,应用程序除了调用其他函数,还可调用库函数。有关详细信息,请参阅从 main()函数中调用库函数。从main()函数中调用库函数。
使用main()函数返回的值调用exit()。
/
从上面就可以看到__user_initial_stackheap的返回值到底是在哪里用到了,
就是“调用 __rt_stackheap_init() 建立栈和堆”这里,实际上还有其它的C库函数有用到,但肯定都是在__main之后,因为__main是C库函数的入口。
我说上面的代码没有调用__user_initial_stackheap,因为很明显,把STARTUP.S从头读到尾,根本没有调用__user_initial_stackheap的语句。那它在哪呢?“rt_misc.h”这个文件里有定义。
/*
* This can be defined to override the standard memory models' way
* of determining where to put the initial stack and heap.
*
* The input parameters R0 and R2 contain nothing useful. The input
* parameters SP and SL are the values that were in SP and SL when
* the program began execution (so you can return them if you want
* to keep that stack).
*
* The two `limit' fields in the return structure are ignored if
* you are using the one-region memory model: the memory region is
* taken to be all the space between heap_base and stack_base.
*/
struct __initial_stackheap {
unsigned heap_base; /* low-address end of initial heap */
unsigned stack_base; /* high-address end of initial stack */
unsigned heap_limit; /* high-address end of initial heap */
unsigned stack_limit; /* low-address end of initial stack */
};
extern __value_in_regs struct __initial_stackheap
__user_initial_stackheap(unsigned /*R0*/, unsigned /*SP*/,
unsigned /*R2*/, unsigned /*SL*/);
由于ARM应用的灵活性,可以通过分散加载文件来定义代码和变量的位置,所以堆栈的地址并不固定,这样,在ARM C库里的函数用到堆栈的地址时候,就用上面定义的变量来代替。
说它是不是多余,其实也不算,因为一般的STARTUP.S都只初始了栈,就是SP。没有初始堆,所以在这个函数里初始堆还是有必要的,而且这个函数的作用主要是返回堆栈的地址,这个地址除了初始化,还可以有其它的作用。毕竟我们不大方便在C语言里直接取SP的地址。
如果没有 B __mian 的话,就没有调用C库,也就用不到初始化C库。而不调用__main,直接进入main()当然是可以实现的,