TIAM3359armを実行しているビーグルボーンで深刻な問題に遭遇しました。私はコードソースを使用してコードをコンパイルしています。軽量IP(lwip)を使用してhttpサーバーを提供するenet_lwipという例の1つをコンパイルしようとしました。
アプリケーションは特定の時点でクラッシュします。デバッグすることで、このコードが原因であることがわかりました。
unsigned int lwIPInit(LWIP_IF *lwipIf)
{
struct ip_addr ip_addr;
struct ip_addr net_mask;
struct ip_addr gw_addr;
unsigned int *ipAddrPtr;
static unsigned int lwipInitFlag = 0;
unsigned int ifNum;
unsigned int temp;
/* do lwip library init only once */
if(0 == lwipInitFlag)
{
lwip_init();
}
これには非常に面白いことが起こります。lwipInitFlagが0に初期化されるため、関数はlwip_init()を呼び出すと予想されます。
さて、これは、lwIPInit関数が最初に呼び出されたときでも発生しません。これは、変数lwipInitFlagが0に設定されていないためです。
なぜなのか知りたいのですが。そのような初期化がコードに含まれている場合、コンパイラはそれをnullにするシーケンスを生成する必要があります。ただし、前に静的修飾子が付いているためか、「そのまま」のままにしておきます。なんで?
lwipInitFlagは、DDRメモリを指す.bssリンカーセクションにあります。このような静的な割り当てが初期化されることをどのように保証できますか?
今のところ、lwIPのコードをハックして、これが機能するかどうかを確認しますが、ライブラリのどこかに、初期化されない別の静的に宣言された変数がある可能性があることを警告します。
これを解決するためのヒントはありますか?
これにさらに情報を追加する:あなたの実りあるヒントの後、私はそれがどのように機能するかについてさらに混乱していると思います。だから:確かに、私はcrt*.oを呼び出したりリンクしたりしません。一方、TIスターターウェアプラットフォームには、BSSクリーンアップを行う初期化asmソースが含まれています。アドレス_bss_startと_bss_endの間でそれを行います。
リンカースクリプトを調べると、すべてがごく普通に見えます。
SECTIONS
{
. = 0x80000000;
. = ALIGN(4);
.startcode :
{
*init.o (.text)
}
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
_bss_start = .;
.bss :
{
*(.bss)
}
. = ALIGN(4);
_bss_end = .;
_stack = 0x87FFFFF8;
}
したがって、_bss_startはBSSブロックの前のアドレスであり、_bss_endはブロックの最後にあります。問題は、Codesourceryが生成するマップです。
生成されたマップファイルでBSSの終わりを見ると、次のことがわかります。
COMMON 0x80088f0c 0x200 ../binary/armv7a/gcc/am335x/system_config/Debug/libsystem_config.a(interrupt.o)
0x80088f0c fnRAMVectors
0x8008910c . = ALIGN (0x4)
0x8008910c _bss_end = .
0x87fffff8 _stack = 0x87fffff8
LOAD ../binary/armv7a/gcc/am335x/drivers/Debug/libdrivers.a
LOAD ../binary/armv7a/gcc/utils/Debug/libutils.a
LOAD ../binary/armv7a/gcc/am335x/beaglebone/platform/Debug/libplatform.a
LOAD ../binary/armv7a/gcc/am335x/system_config/Debug/libsystem_config.a
LOAD /opt/CodeSourcery/arm-none-eabi/lib//libc.a
LOAD /opt/CodeSourcery/lib/gcc/arm-none-eabi/4.5.2//libgcc.a
LOAD ../binary/armv7a/gcc/am335x/drivers/Debug/libdrivers.a
LOAD ../binary/armv7a/gcc/utils/Debug/libutils.a
LOAD ../binary/armv7a/gcc/am335x/beaglebone/platform/Debug/libplatform.a
LOAD ../binary/armv7a/gcc/am335x/system_config/Debug/libsystem_config.a
LOAD /opt/CodeSourcery/arm-none-eabi/lib//libc.a
LOAD /opt/CodeSourcery/lib/gcc/arm-none-eabi/4.5.2//libgcc.a
OUTPUT(Debug/bbdidt.out elf32-littlearm)
.bss.pageTable 0x8008c000 0x4000
.bss.pageTable
0x8008c000 0x4000 Debug/enetLwip.o
.bss.ram 0x80090000 0x4
.bss.ram 0x80090000 0x4 Debug/lwiplib.o
明らかに「何か」があります。_bss_endの後に別のBSSセクションがあり、ゼロ化されることが期待される多くのものが含まれていますが、ゼロ化は_bss_endで指定されたアドレスで終了するため、ゼロ化されません。
これがこのように行われる理由として考えられるのは、pageTableが静的に宣言されており、16kiBの境界アドレスが必要であるためです。
static volatile unsigned int pageTable[4*1024] __attribute__((aligned(16*1024)));
したがって、最後に宣言されたBSSセグメントとpageTableの間にギャップがあるため、_bss_endはbssセグメントの中央に配置されます。
ここで問題となるのは、リンカー(このarm-none-eabi-ldに使用している)に、_bss_endは実際にはBSSの最後にあり、途中ではないことを伝える方法です。
どうもありがとう