I'm developing an embedded application using GCC/G++ compiled for arm-eabi. Due to resource constraints, I'm trying to disable the standard C++ exception handling. I'm compiling the code with "-fno-exceptions -nostartfiles -ffreestanding".
我正在使用为arm-eabi编译的GCC / G ++开发嵌入式应用程序。由于资源限制,我试图禁用标准C ++异常处理。我正在使用“-fno-exceptions -nostartfiles -ffreestanding”编译代码。
When a global instance of a class exists, and that class contains an instance of another class as a member, then a lot of exception handling code is being linked in. This wouldn't be so bad, except that it's also bringing in lots of stdio stuff, like printf, fopen, fclose and other FILE functions. This application has no filesystem, and even if it did, these functions waste too much code space.
当一个类的全局实例存在,并且该类包含另一个类的实例作为成员时,则链接了许多异常处理代码。这不会那么糟糕,除了它还带来了很多stdio的东西,比如printf,fopen,fclose和其他FILE函数。此应用程序没有文件系统,即使这样做,这些功能也会浪费太多代码空间。
I understand that even with -fno-exceptions, G++ links in an operator new that uses exceptions, because the library doesn't have a non-exception-using operator new (except new(nothrow)). I created replacements for operator new and delete, and these are linked into the output as well as the unwanted standard-library functions.
我理解即使使用-fno-exceptions,G ++链接在使用异常的operator new中,因为库没有非异常使用的operator new(new(nothrow)除外)。我为operator new和delete创建了替换,它们被链接到输出以及不需要的标准库函数。
What puzzles me is that I'm not calling new anywhere. It's only when a global object contains another object that all this code is linked in.
令我困惑的是,我不会在任何地方打电话给新人。只有当一个全局对象包含另一个对象时才会链接所有这些代码。
For example:
class UartA {
...
private:
Ringbuffer* rxbuf;
};
class UartB {
...
private:
Ringbuffer rxbuf;
};
If a global instance of UartA is created, the exception handling, operator new, and stdio stuff are not linked in. This is what I want.
如果创建了UartA的全局实例,则不会链接异常处理,operator new和stdio内容。这就是我想要的。
If a global instance of UartB is created (where rxbuf is an instance instead of a pointer), the unwanted code is linked in.
如果创建了UartB的全局实例(其中rxbuf是实例而不是指针),则链接不需要的代码。
Neither UartA nor UartB use operator new, exceptions or stdio. They differ only by the type of rxbuf.
UartA和UartB都不使用operator new,exception或stdio。它们的区别仅在于rxbuf的类型。
Can you suggest how to prevent linking the extra code? Also, why is this being linked in for UartB, but not UartA?
你能建议如何防止链接额外的代码吗?另外,为什么这与UartB相关联,而不是UartA?
3 个解决方案
#1
I think the closest you can get is compiling and linking with -fno-exceptions and -fno-rtti. If there's a better way to get rid of the rest, I'd be glad to hear it myself.
我认为最接近的是编译和链接-fno-exceptions和-fno-rtti。如果有更好的方法摆脱休息,我会很高兴自己听到。
As far as getting rid of new, try -nostdlib.
至于摆脱新的,尝试-nostdlib。
#2
since you are basically doing the things that an OS developer would do to get a standalone c or c++ environment. You may want to look into just using a custom linker script. You just need to be careful because things like global constructors no longer happen automatically..but you will also not get anything you didn't explicitly ask for (and it isn't hard to write the code to call the global constructors). Here's the linker script from my OS.
因为你基本上是在做OS开发人员为了获得一个独立的c或c ++环境所做的事情。您可能希望仅使用自定义链接描述文件。你只需要小心,因为全局构造函数之类的东西不再自动发生。但是你也没有得到任何你没有明确要求的东西(并且编写代码来调用全局构造函数并不困难)。这是我操作系统的链接描述文件。
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 = .;
}
It probably does more than you need (aligns sections to 4k boundaries, has all symbols at > 3GB mark) but is a good starting place.
它可能比您需要的更多(将部分对齐到4k边界,所有符号都大于3GB标记)但是它是一个很好的起点。
You can use it like this:
你可以像这样使用它:
ld -T link_script.ld *.o -lc -o appname
the "-lc" should link in libc as well if that's what you want.
“-lc”应该在libc中链接,如果这是你想要的。
#3
You might try trapping new to see if it is really being called anyway.
您可以尝试捕获new以查看它是否真的被调用。
New can occur implicitly under some circumstances, such as copy-construction.
在某些情况下,例如复制构造,可能会隐式发生新的情况。
You may be able to remove these by writing your code slightly differently.
您可以通过略微区别地编写代码来删除它们。
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter11_013.html
#1
I think the closest you can get is compiling and linking with -fno-exceptions and -fno-rtti. If there's a better way to get rid of the rest, I'd be glad to hear it myself.
我认为最接近的是编译和链接-fno-exceptions和-fno-rtti。如果有更好的方法摆脱休息,我会很高兴自己听到。
As far as getting rid of new, try -nostdlib.
至于摆脱新的,尝试-nostdlib。
#2
since you are basically doing the things that an OS developer would do to get a standalone c or c++ environment. You may want to look into just using a custom linker script. You just need to be careful because things like global constructors no longer happen automatically..but you will also not get anything you didn't explicitly ask for (and it isn't hard to write the code to call the global constructors). Here's the linker script from my OS.
因为你基本上是在做OS开发人员为了获得一个独立的c或c ++环境所做的事情。您可能希望仅使用自定义链接描述文件。你只需要小心,因为全局构造函数之类的东西不再自动发生。但是你也没有得到任何你没有明确要求的东西(并且编写代码来调用全局构造函数并不困难)。这是我操作系统的链接描述文件。
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 = .;
}
It probably does more than you need (aligns sections to 4k boundaries, has all symbols at > 3GB mark) but is a good starting place.
它可能比您需要的更多(将部分对齐到4k边界,所有符号都大于3GB标记)但是它是一个很好的起点。
You can use it like this:
你可以像这样使用它:
ld -T link_script.ld *.o -lc -o appname
the "-lc" should link in libc as well if that's what you want.
“-lc”应该在libc中链接,如果这是你想要的。
#3
You might try trapping new to see if it is really being called anyway.
您可以尝试捕获new以查看它是否真的被调用。
New can occur implicitly under some circumstances, such as copy-construction.
在某些情况下,例如复制构造,可能会隐式发生新的情况。
You may be able to remove these by writing your code slightly differently.
您可以通过略微区别地编写代码来删除它们。
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter11_013.html