GCC 编译从入门到入坟

这是一篇 GCC 编译的疑难杂症文章

常见问题

gcc 无法找到常用头文件

当我们利用如下命令查看 gcc 所使用的头文件目录时

1
`gcc -print-prog-name=cc1` -v

发现目录为编译该 gcc 的人所使用的目录,而我们又没有该目录

这种情况就需要自己去用-I来指定头文件目录了(视问题而定,不一定能解决)

musl-gcc 问题

弱类型问题

当我们看见如下错误

1
2
alias.c: error: ‘nvram_commit_adv’ aliased to undefined symbol ‘nvram_commit’
  233 | int nvram_commit_adv(int) __attribute__((alias("nvram_commit")));

可以在alias.c中加一行同名空函数来解决问题

1
static int nvram_commit() {}

gethostbyname 函数崩溃

问题来源: 用 musl-gcc 静态编译带有gethostbyname函数的程序产生了段错误

Ps:musl 存在特殊的静态堆内存区

在 Glibc 中,堆从一开始就动态申请和释放,而在 musl 中,程序开始的时候会把程序和 libc 空闲的区域当做堆内存(静态内存),优先从这里面划分空间,这部分空间用完之后再通过 mmap 进行分配

问题原因: 静态链接下使用到了这种静态堆内存区,返回的是 64 位的地址,然后下一句汇编cdqe会按照 eax 的最高位,拓展出 rax 高 32 位的所有位,使其变为一个无效地址

汇编演示如下:

*RAX  0x7ffff7ff8050 —▸ 0x7ffff7ff809c ◂— '127.0.0.1'
   0x4091f3 <main+86>     call   gethostbyname@plt                      <gethostbyname@plt> 
 ► 0x4091f8 <main+91>     cdqe

之后地址会变为

*RAX  0xfffffffff7ff8050

导致最终我们得到了一个错误的struct hostent *类型的地址

解决方法:

发现编译的时候加了参数-std=c99,删掉这个参数就好了