L6305W: Image does not have an entry point. (Not specified or not set due to multiple choices.)

做项目的时候遇到此问题,现在终于解决了,把过程罗列出来供大家参考。


1. 简单介绍一下项目。这个项目是为嵌入式平台开发的,不同的功能模块分别编译成独立库文件a.lib, b.lib, c.lib,d.lib...

最后和RTOS编译成的诸多.o文件链接在一起生成一个bootable 的arm平台运行的bin文件。

ENTRY POINT在 RTOS中的int.s中指定。


编译链接步骤简单介绍如下:

      (1)分别生成各个.c文件的目标文件
      tcc  -c -li  -fK  -dwarf2 -g+ -O0 -apcs /interwork -Ez -Ec   -o  binaries/obj/a_file1.o a_file1.c

      tcc  -c -li  -fK  -dwarf2 -g+ -O0 -apcs /interwork -Ez -Ec   -o  binaries/obj/a_file1.o a_file2.c

      tcc  -c -li  -fK  -dwarf2 -g+ -O0 -apcs /interwork -Ez -Ec   -o  binaries/obj/a_file1.o a_file3.c

      tcc  -c -li  -fK  -dwarf2 -g+ -O0 -apcs /interwork -Ez -Ec   -o  binaries/obj/a_file1.o a_file4.c

       .....

    (2)各个模块分别链接成库文件
    armar -rc ./binaries/lib/a.lib ./binaries/obj/a_file1.o ./binaries/obj/a_file2.o ./binaries/obj/a_file3.o ./binaries/obj/a_file4.o
    类似方法分别生成b.lib, c.lib, d.lib....
   
    (3)最后生成bootable bin wlan_arm.bin文件,出现warning.
    armlink -d  -strict -s -callgraph -Xref -map -list ../../bin/wlan_arm.map -o ../../bin/wlan_arm.axf -scatter link_ram.ld obj/syapp.obj obj/symain.obj /lib/a.lib /lib/b.lib /lib/c.lib /lib/d.lib                
fromelf -bin ../../bin/wlan_arm.axf ../../bin/wlan_arm.bin
L6305W: Image does not have an entry point. (Not specified or not set due to multiple choices.)
Finished: 0 information, 1 warning and 0 error messages.

2. 问题分析
    2.1问题出现
        模块d升级后出现了此L6305W warning. 由链接器的文档说明,要么没指定这个ENTRY POINT, 要么就是指定了多个ENTRY POINT. 查看armlink -map生成的映像文件,看到多了一个默认的entry point " __main()".
        int.o中我们已经指定了ENTRY POINT, main()函数应该是编译器自己默认编译成loadable的bin文件的时候默认的普通ENTRY POINT. 普通的loadable的bin文件是需要操作系统(OS)为其分配内存并加载到内存中的,其中上下文的地址都是相对地址,需要OS为其分配内存后,加上分配内存的基址才是它真正的运行地址。但是bootable的bin文件就不同了,它的上下文中的地址直接就是实际运行时刻的内存地址。其中细节在此不多介绍,而且不同的OS,不同的CPU, 对loadable的文件应该有不同的地址处理。如果有对细节了解更系统,更深刻的朋友,请赐教。
    ===============================================
    Memory Map of the image

      Image entry point : Not specified.

      Load Region LOAD_RAM (Base: 0x10000000, Size: 0x00278544, Max: 0xffffffff, ABSOLUTE)

    Execution Region text (Base: 0x10000000, Size: 0x00238490, Max: 0xffffffff, ABSOLUTE)

    Base Addr    Size         Type   Attr  Idx  E Section Name        Object

    0x10000000   0x00000040   Code   RO  3785   * vectors             int.o(plus_specific.lib)
    0x10000040   0x000000dc   Code   RO  13462   * !!!                 __main.o(c_t__un.l)
    =====================================================   
    在此我也有几个问题不是非常明白。比如,ENTRY POINT对于编译器的真正意义是什么?是不是,编译器会从这个ENTRY POINT开始找寻链接关系,只要是从此处开始逐层调用引用到得文件就链接到bin文件中,引用不到的自然就不链接进来了。
    还有就是ENTRY POINT是不是一定放在地址的最开始?
    再者就是,对于loadable的文件,有没有办法自己指定ENTRY POINT,而不是用默认的main()?
   
    2.2发现原因
   
    模块d之前没有使用过strncasecmp(),但是升级后却使用了,虽然在自己本身模块中已经定义了此函数。但是从armlink -Xref 生成的引用关系中明确看到它使用的是c.lib中定义的strncasecmp()。(当然还有其他函数也出现类似情况,现在仅跟踪此线索来解决问题。)strncasecmp() 在c_file1.o中定义,此文件中其他函数引用到exit.o, exit.o 引用到kernel.o, kernel.o引用到c_file3.o, c_file3.o引用到__main,这个应该就是默认的ENTRY POINT了。于是俺们滴bin文件中就多了个ENTRY POINT.(引用关系参考下面Section Cross References)
如果将链接时的顺序倒过来,即d.lib 在c.lib之前,那么d.lib就会乖乖用自己的strncasecmp()了。
    ================================================================================
    Section Cross References
   
        d_file2.o(.text) refers to c_file1.o(.text) for strncasecmp
        c_file1.o(.text) refers to exit.o(.text) for exit
        exit.o(.text) refers to kernel.o(.text) for __rt_exit
        kernel.o(.text) refers to c_file3.o(.text) for main
        c_file3.o(.text) refers (Special) to __main.o(!!!) for __main
    ================================================================================   
   
   

3. 问题解决
    看了下引用关系,确定像c_file3.o此一类的文件并没有真正用到,只是automake的时候把此模块中的文件全部编译了才引入到c.lib中。于是,重写Makefile, 仅编译指定的几个.c文件到c.lib中, c_file3.o不再出现在c.lib中。
    自此,天下太平。
   
    (当然,如果c_file3.o中的函数,你需要引用,那么就只能换个方法了。)

你可能感兴趣的:(c,image,File,嵌入式,makefile,编译器)