当前位置:  开发笔记 > 编程语言 > 正文

GCC创建共享对象而不是可执行二进制文件

如何解决《GCC创建共享对象而不是可执行二进制文件》经验,为你挑选了2个好方法。

我有一个正在建设的图书馆.当我运行以下任何一个时,我的所有对象都会连续编译和链接: ar rcs lib/libryftts.a $^

gcc -shared $^ -o lib/libryftts.so

在我的Makefile中.我也能够成功安装它们/usr/local/lib 当我用nm测试文件时,所有的功能都在那里.我的问题是,当我跑步gcc testing/test.c -lryftts -o test && file ./testgcc testing/test.c lib/libryftts.a -o test && file ./test 它说:

test: ELF 64-bit LSB shared object而不是test: ELF 64-bit LSB executable像我期望的那样.我究竟做错了什么?



1> Employed Rus..:

我究竟做错了什么?

没有.

听起来您的GCC -pie默认配置为构建二进制文件.这些二进制文件实际上共享库(类型ET_DYN),除了它们像普通可执行文件一样运行.

所以你应该运行你的二进制文件,并且(如果它有效)不用担心它.

或者您可以链接您的二进制文件,gcc -no-pie ...并且应该生成PIE类型的不可执行文件ET_EXEC,对此file将说明ELF 64-bit LSB executable.


如果你打算使用`-no-pie`,你也应该使用`-fno-pie`来获得更高效的代码.(参见/sf/ask/17360801/)
@dylan您必须构建自己的编译器.当你"配置"它时,不要指定`--enable-default-pie`,你将全部设置好.

2> Ciro Santill..:

file 5.36清楚地说

file如果可执行文件是否为PIE,则5.36实际上会清晰地打印出来,如下所示:https : //unix.stackexchange.com/questions/89211/how-to-test-whether-a-linux-binary-was-compiled-as-位置无关代码/ 435038#435038

例如,PIE可执行文件显示为:

main.out:ELF 64位LSB Pie可执行文件,x86-64,版本1(SYSV),动态链接,未剥离

非PIE则为:

main.out:ELF 64位LSB可执行文件,x86-64,版本1(SYSV),静态链接,未剥离

该功能是在5.33中引入的,但仅进行了简单的chmod +x检查。在此之前,它只是shared object为PIE 打印。

在5.34中,本来打算开始检查更专业的DF_1_PIEELF元数据,但是由于在提交9109a696f3289ba00eaa222fd432755ec4287e28的实现中存在错误,它实际上使事情变得混乱,并将GCC PIE可执行文件显示为shared objects

该错误已在5.36 修订为03084b161cf888b5286dbbcd964c31ccad4f64d9。

该错误特别存在于具有file5.34的Ubuntu 18.10中。

ld -pie由于巧合,在链接汇编代码时它不会显示出来。

源代码细分显示在file此答案的“ 5.36源代码分析”部分。

Linux内核5.0根据以下信息确定是否可以使用ASLR: ET_DYN

file“混乱” 的根本原因是PIE可执行文件和共享库都是位置无关的,可以放置在随机存储位置中。

在fs / binfmt_elf.c,内核仅接受这两种类型的ELF文件:

/* First of all, some simple consistency checks */
if (interp_elf_ex->e_type != ET_EXEC &&
        interp_elf_ex->e_type != ET_DYN)
        goto out;

然后,仅将for ET_DYN设置load_bias为不为零的值。该load_bias是那么什么决定了ELF偏移:如何在Linux中确定的PIE可执行文件的文本部分的地址?

/*
 * If we are loading ET_EXEC or we have already performed
 * the ET_DYN load_addr calculations, proceed normally.
 */
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
        elf_flags |= elf_fixed;
} else if (loc->elf_ex.e_type == ET_DYN) {
        /*
         * This logic is run once for the first LOAD Program
         * Header for ET_DYN binaries to calculate the
         * randomization (load_bias) for all the LOAD
         * Program Headers, and to calculate the entire
         * size of the ELF mapping (total_size). (Note that
         * load_addr_set is set to true later once the
         * initial mapping is performed.)
         *
         * There are effectively two types of ET_DYN
         * binaries: programs (i.e. PIE: ET_DYN with INTERP)
         * and loaders (ET_DYN without INTERP, since they
         * _are_ the ELF interpreter). The loaders must
         * be loaded away from programs since the program
         * may otherwise collide with the loader (especially
         * for ET_EXEC which does not have a randomized
         * position). For example to handle invocations of
         * "./ld.so someprog" to test out a new version of
         * the loader, the subsequent program that the
         * loader loads must avoid the loader itself, so
         * they cannot share the same load range. Sufficient
         * room for the brk must be allocated with the
         * loader as well, since brk must be available with
         * the loader.
         *
         * Therefore, programs are loaded offset from
         * ELF_ET_DYN_BASE and loaders are loaded into the
         * independently randomized mmap region (0 load_bias
         * without MAP_FIXED).
         */
        if (elf_interpreter) {
                load_bias = ELF_ET_DYN_BASE;
                if (current->flags & PF_RANDOMIZE)
                        load_bias += arch_mmap_rnd();
                elf_flags |= elf_fixed;
        } else
                load_bias = 0;

我通过以下实验进行了确认:对于gcc和ld中与位置无关的可执行文件,-fPIE选项是什么?

file 5.36行为细分

file从源头研究了工作原理之后。我们将得出以下结论:

如果 Elf32_Ehdr.e_type == ET_EXEC

打印 executable

否则,如果 Elf32_Ehdr.e_type == ET_DYN

如果DT_FLAGS_1存在动态部分条目

如果DF_1_PIE在中设置DT_FLAGS_1

打印 pie executable

其他

打印 shared object

其他

文件是否可由用户,组或其他人执行

打印 pie executable

其他

打印 shared object

以下是一些实验可以证实这一点:

Executable generation        ELF type  DT_FLAGS_1  DF_1_PIE  chdmod +x      file 5.36
---------------------------  --------  ----------  --------  -------------- --------------
gcc -fpie -pie               ET_DYN    y           y         y              pie executable
gcc -fno-pie -no-pie         ET_EXEC   n           n         y              executable
gcc -shared                  ET_DYN    n           n         y              pie executable
gcc -shared                  ET_DYN    n           n         n              shared object
ld                           ET_EXEC   n           n         y              executable
ld -pie --dynamic-linker     ET_DYN    y           y         y              pie executable
ld -pie --no-dynamic-linker  ET_DYN    y           y         y              pie executable

已在Ubuntu 18.10,GCC 8.2.0,Binutils 2.31.1中进行了测试。

每种实验的完整测试示例在以下位置描述:

gcc -piegcc -no-pie:gcc和ld中与位置无关的可执行文件的-fPIE选项是什么?

请记住,-pie自Ubuntu 17.10起,默认情况下已启用该功能,相关信息:x86-64 Linux中不再允许使用32位绝对地址?

gcc -shared.so共享库):https : //github.com/cirosantilli/cpp-cheat/tree/b80ccb4a842db52d719a16d3716b02b684ebbf11/shared_library/basic

ld实验:如何在Linux中创建静态链接的位置无关可执行ELF?

ELF typeDF_1_PIE分别通过以下方式确定:

readelf --file-header main.out | grep Type
readelf --dynamic     main.out | grep FLAGS_1

file 5.36源代码分析

要分析的密钥文件是magic / Magdir / elf。

这种不可思议的格式仅取决于固定位置的字节值来确定文件类型。

格式本身记录在:

man 5 magic

因此,在这一点上,您将需要准备以下文件:

ELF标头部分的http://www.sco.com/developers/devspecs/gabi41.pdf ELF标准

http://www.cirosantilli.com/elf-hello-world/#elf-header我的ELF文件格式介绍和细分

在文件末尾,我们看到:

0       string          \177ELF         ELF
!:strength *2
>4      byte            0               invalid class
>4      byte            1               32-bit
>4      byte            2               64-bit
>5      byte            0               invalid byte order
>5      byte            1               LSB
>>0     use             elf-le
>5      byte            2               MSB
>>0     use             \^elf-le

\177ELF是每个ELF文件开头的4个魔术字节。\177是的八进制0x7F

然后,通过与Elf32_Ehdr标准中的结构进行比较,我们看到字节4(第5个字节,魔术标识符之后的第一个字节)确定ELF类:

e_ident[EI_CLASSELFCLASS]

其一些可能的值为:

ELFCLASS32 1
ELFCLASS64 2

file源代码中,我们有:

1 32-bit
2 64-bit

32-bit64-bit是字符串file输出到标准输出!

因此,现在我们shared object在该文件中搜索,然后导致:

0       name            elf-le
>16     leshort         0               no file type,
!:mime  application/octet-stream
>16     leshort         1               relocatable,
!:mime  application/x-object
>16     leshort         2               executable,
!:mime  application/x-executable
>16     leshort         3               ${x?pie executable:shared object},

因此,这elf-le是一种标识符,已包含在代码的前一部分中。

字节16正是ELF类型:

Elf32_Ehdr.e_type

其某些值是:

ET_EXEC 2
ET_DYN  3

因此,ET_EXEC总是打印为executable

ET_DYN但是有两种可能性,具体取决于${x

pie executable

shared object

${x问:文件是否可以由用户,组或其他人执行?如果是,请显示pie executable,否则shared object

此扩展是在的varexpand函数中完成的src/softmagic.c

static int
varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
{
    [...]
            case 'x':
                    if (ms->mode & 0111) {
                            ptr = t;
                            l = et - t;
                    } else {
                            ptr = e;
                            l = ee - e;
                    }
                    break;

但是,还有另外一种技巧!在src/readelf.cfunction中dodynamic,如果存在DT_FLAGS_1动态节(PT_DYNAMIC)的标志条目,则st->mode存在或不存在DF_1_PIE标志将覆盖其中的权限:

case DT_FLAGS_1:
        if (xdh_val & DF_1_PIE)
                ms->mode |= 0111;
        else
                ms->mode &= ~0111;
        break;

5.34中的错误是初始代码编写为:

    if (xdh_val == DF_1_PIE)

这意味着,如果设置了另一个标志(默认情况下GCC会这样做),则可DF_1_NOW执行文件显示为shared object

DT_FLAGS_1标志条目不会在ELF标准描述所以它必须是一个Binutils的扩展。

该标志在Linux内核5.0或glibc 2.27中没有任何用处,因此我似乎只是在提供信息,以指示文件是否为PIE。

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有