问题 是否有一种简单的方法可以使gcc省略crtbegin.o / crtend.o?


除了使用 -nostdlib 和链接 crt1.o -lc -lgcc 你自己,有什么简单的方法来阻止gcc的链接 crtbegin[S].o 和 crtend[S].o?这些文件不是那么大,但我正在玩小型二进制文件,并希望删除C程序不需要的无用的C ++支持代码。 (据推测,如果您正在使用带有全局对象变量的C ++库,gcc甚至会将它们链接到C程序。我会饶恕每个人如何在全局对象被引用的地方生成安全的一次性初始化调用。 C ++模块,而不是在之前初始化全局对象 main...)

我不会反对攻击gcc specs 文件以使C ++支持文件的链接以某种方式为条件,但我不确定如何做到这一点。也许这已经很好了?


2857
2017-11-11 06:58


起源

我相信他们是需要的 __attribute__ ((constructor)) (和 destructor)功能也是。 (而且我远非C ++专家,但我被告知要符合标准,全球构造函数必须先发生 main() 叫做。) - caf
@caf:我的印象是C ++标准指定在程序调用和第一次使用对象之间的未指定时间调用构造函数(当然还有未指定的顺序,除了一个对象引用另一个对象的情况)因此调用“第一次使用它”)。你有相反的提法吗? - R..
可能是一个“吸蛋教”,但你尝试过使用过 gcc 编译并直接进入你的系统链接器(可能是 ld)对于实际的链接步骤,以便您可以更好地控制链接? - CB Bailey
@Charles:我知道我可以这样做,但是我必须自己去找标准的库文件和库路径。它比...更痛苦 gcc -nostdlib。 - R..
我目前正在使用 specs 文件黑客以跳过链接这些文件;在shell中写了一个gcc包装器,就像 exec /usr/bin/gcc --specs /usr/lib/gcc/specs-no-c++ "$@"。对我来说这是最简单的方法。 - Low power


答案:


gcc -wrapper sh,-c,'z= ; for i ; do [ "$z" ] || set -- ; z=1 ;
    case "$i" in *crtbegin*.o|*crtend*.o) ;; *) set -- "$@" "$i" ;; esac ;
    done ; exec "$0" "$@"'

7
2017-12-30 01:37



有人可以解释上面脚本中发生的事情吗? - 4aRk Kn1gh7
@ 4aRkKn1gh7: -wrapper 选项获取gcc以调用它通过包装器程序运行的外部命令。包装器程序是一个shell脚本,它删除任何匹配的参数 *crtbegin*.o 要么 *crtend*.o 在调用请求的命令之前。它只是在命令行上内联编写而不是将脚本保存到文件中。 - R..


我想你需要的 -nostartfiles 选项。这就是我对嵌入式东西的需求。


3
2017-11-11 07:17



这是一个好的开始(没有双关语意),但它也省略了 crt1.o 其中包含 _start 入口点。 - R..
@R ..:我相信你可以在链接描述文件中设置ENTRYPOINT。 - leppie
是的,我知道我可以这样做,但这比找到路径要糟糕得多 crt1.o 并使用 gcc 命令行链接。基本上我一直在寻找最接近便携式方式的东西,让gcc不要连接不必要的东西,答案似乎是没有。 - R..
crt1.o不是C ++支持垃圾。这是提取C代码的正常入口点 argc, argv,以及从内核给予程序的初始状态指向环境的指针,并使用它来调用 exit(main(argc,argv)); - R..
顺便一提, gcc -print-file-name=crt1.o 会给你路径名 crt1.o 您可以使用它在传递后重新添加它 -nostartfiles。 - R..