6

arm-eabi 用にコンパイルされた GCC/G++ を使用して組み込みアプリケーションを開発しています。リソースの制約により、標準の C++ 例外処理を無効にしようとしています。「-fno-exceptions -nostartfiles -ffreestanding」でコードをコンパイルしています。

クラスのグローバル インスタンスが存在し、そのクラスに別のクラスのインスタンスがメンバーとして含まれている場合、多くの例外処理コードがリンクされています。 printf、fopen、fclose、その他の FILE 関数などの stdio のもの。このアプリケーションにはファイルシステムがなく、たとえあったとしても、これらの関数はコード スペースを浪費しすぎます。

ライブラリには例外を使用しない演算子 new (new(nothrow) を除く) がないため、-fno-exceptions を使用しても、G++ は例外を使用する演算子 new にリンクすることを理解しています。new 演算子と delete 演算子の代替を作成しました。これらは、不要な標準ライブラリ関数だけでなく、出力にもリンクされています。

私を困惑させているのは、私がどこにも新しいと呼んでいないということです。グローバル オブジェクトに、このすべてのコードがリンクされている別のオブジェクトが含まれている場合のみです。

例えば:

class UartA {
...
private:
  Ringbuffer* rxbuf;
};

class UartB {
...
private:
  Ringbuffer rxbuf;
};

UartA のグローバル インスタンスが作成された場合、例外処理、新しい演算子、および標準入出力はリンクされません。これが私の望みです。

UartB のグローバル インスタンスが作成される場合 (ここで、rxbuf はポインターではなくインスタンスです)、不要なコードがリンクされます。

UartA も UartB も、演算子 new、例外、または stdio を使用しません。rxbuf のタイプのみが異なります。

余分なコードのリンクを防ぐ方法を提案できますか? また、これが UartB にリンクされているのに、UartA にリンクされていないのはなぜですか?

4

3 に答える 3

6

基本的に、OS 開発者がスタンドアロンの c または c++ 環境を取得するために行うことを行っているためです。カスタム リンカー スクリプトの使用だけを検討することをお勧めします。グローバル コンストラクターなどの処理は自動的に行われなくなるため、注意が必要です。ただし、明示的に要求していないものは取得されません (グローバル コンストラクターを呼び出すコードを記述することは難しくありません)。これが私のOSのリンカースクリプトです。

OUTPUT_FORMAT("elf32-i386")
ENTRY(start)

virt = 0xc0100000; /* 3.1 gig */
phys = 0x00100000; /* 1 meg */

SECTIONS
{ 
    .text virt : AT(phys) 
    {
        code = .; _code = .; __code = .;
        *(.text)
        *(.gnu.linkonce.t*)
        . = ALIGN(4096); 
    }

    .rodata : AT(phys + (rodata - code))
    {
        rodata = .; _rodata = .; __rodata = .;
        *(.rodata*)
        *(.gnu.linkonce.r*)
        __CTOR_LIST__ = .;
        LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) 
        *(.ctors) 
        LONG(0) 
        __CTOR_END__ = .; 

        __DTOR_LIST__ = .; 
        LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) 
        *(.dtors) 
        LONG(0) 
        __DTOR_END__ = .; 
        . = ALIGN(4096); 
    }

    .data : AT(phys + (data - code))
    {
        data = .; _data = .; __data = .;    
        *(.data)
        *(.gnu.linkonce.d*)
        . = ALIGN(4096); 
    }

    .tbss : AT(phys + (tbss - code)) 
    {
        tbss = .; _tbss = .; __tbss = .;
        *(.tbss)
        *(.tbss.*)
        . = ALIGN(4096); 
    }

    .bss : AT(phys + (bss - code)) 
    {
        bss = .; _bss = .; __bss = .;
        *(.bss)
        *(.bss.*)
        *(COMMON)
        *(.gnu.linkonce.b*)
        . = ALIGN(4096); 
    }

    end = .; _end = .; __end = .;
}

おそらく必要以上のことを行います (セクションを 4k 境界に揃え、すべてのシンボルを 3GB マーク以上に配置します) が、出発点としては適しています。

次のように使用できます。

ld -T link_script.ld *.o -lc -o appname

「-lc」は、必要に応じてlibcにもリンクする必要があります。

于 2009-06-15T21:15:41.580 に答える
5

最も近いのは、-fno-exceptions と -fno-rtti を使用してコンパイルおよびリンクすることだと思います。残りを取り除くためのより良い方法があれば、私はそれを自分で聞いてうれしいです.

new を取り除く限り、-nostdlib を試してください。

于 2009-06-15T20:40:37.187 に答える
0

とにかくそれが本当に呼び出されているかどうかを確認するために、新しいトラップを試してみてください。

新規は、コピー構築などの特定の状況下で暗黙的に発生する可能性があります。

コードを少し異なる方法で記述することで、これらを削除できる場合があります。

http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter11_013.html

于 2009-06-15T21:08:06.607 に答える