使用 gcc 理解共享库

发布于 2024-09-27 01:03:17 字数 1630 浏览 0 评论 0原文

我试图理解 C 中共享库的以下行为

一号机

$ cat one.c 
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc one.c -o one -O3
$ ldd one
    linux-gate.so.1 =>  (0x00331000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00bc2000)
    /lib/ld-linux.so.2 (0x006dc000)
$ cat two.c 
int main() {
    int i = 0;
}
$ gcc two.c -o two -O3
$ ldd two
    linux-gate.so.1 =>  (0x006f7000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
    /lib/ld-linux.so.2 (0x00eb0000)
$

机器二

$ cat three.c
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc three.c -o three -O3
$ ldd three
    /usr/lib/libcwait.so (0xb7ffd000)
    libc.so.6 => /lib/tls/i686/nosegneg/libc.so.6 (0x002de000)
    /lib/ld-linux.so.2 (0x002bf000)
$

目前我还没有完全理解一些事情:

  • 括号中给出的地址(例如,(0x002de000))是什么意思?

    即使对于同一台机器上的同一个库,这些地址也是不同的,这表明这些是加载这些库的内存位置的地址。但是,如果这是真的,为什么这些库会加载到内存中(我还没有执行程序,它们不应该只在运行时加载吗?)。

  • 为什么two需要任何库?我使用了-O3,汇编器输出为

    <前><代码>$ gcc Two.c -S -O3 $ 猫二.s .文件“两个.c” 。文本 .p2align 4,,15 .global主文件 .type main, @function 主要的: 推入%ebp movl %esp, %ebp 人口%ebp 雷特 .size 主,.-main .ident“GCC:(Ubuntu 4.4.3-4ubuntu5)4.4.3” .section .note.GNU-stack,"",@progbits $

    到底需要什么库?

  • 在机器 2 上,为什么使用 /usr/lib/libcwait.so 而不是 linux-gate.so.1

    我认为这是因为机器二上的内核非常旧(2.6.9)并且库linux-gate.so.1不可用。这是原因吗?

I am trying to understand the following behavior of shared libraries in C

Machine One

$ cat one.c 
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc one.c -o one -O3
$ ldd one
    linux-gate.so.1 =>  (0x00331000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00bc2000)
    /lib/ld-linux.so.2 (0x006dc000)
$ cat two.c 
int main() {
    int i = 0;
}
$ gcc two.c -o two -O3
$ ldd two
    linux-gate.so.1 =>  (0x006f7000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
    /lib/ld-linux.so.2 (0x00eb0000)
$

Machine Two

$ cat three.c
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc three.c -o three -O3
$ ldd three
    /usr/lib/libcwait.so (0xb7ffd000)
    libc.so.6 => /lib/tls/i686/nosegneg/libc.so.6 (0x002de000)
    /lib/ld-linux.so.2 (0x002bf000)
$

A few things I don't fully understand at present:

  • What does the address given in brackets (for example, (0x002de000)) mean?

    These addresses are different even for the same library on the same machine, which suggests these are addresses of the locations in memory where these libraries are loaded. But, if that is true, why are these libraries loaded in memory at all (I did not execute the programs yet, shouldn't they be loaded only at runtime?).

  • Why does two need any libraries at all? I have used -O3, and the assembler output is

    $ gcc two.c -S -O3 
    $ cat two.s
        .file   "two.c"
        .text
        .p2align 4,,15
    .globl main
        .type   main, @function
    main:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section    .note.GNU-stack,"",@progbits
    $
    

    What is the need of any libraries at all?

  • On Machine Two, why is /usr/lib/libcwait.so being used instead of linux-gate.so.1?

    I think this is because the kernel on Machine Two is very old (2.6.9) and the library linux-gate.so.1 is not available. Is that the reason?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

虐人心 2024-10-04 01:03:17

括号中给出的地址(例如,(0x002de000))是什么意思?

它是加载库的(虚拟)内存地址。
最近的系统可以提供库加载位置的随机化,所以
该地址可能因调用而异。

它们不应该只在运行时加载吗?

是的,他们是。 ldd 经历的过程与
但在运行时完成,以便能够弄清楚各种事情。

为什么两个人都需要任何库?

libc.so.6 是标准 C 库(以及其他东西,例如内核接口),并且始终在默认情况下链接。 gcc 有选项来控制这一点,例如 -nostdlib 标志

ld-linux.so 是动态加载器,负责加载/重新定位其他共享库并运行您的应用程序。 ld-linux.so 的联机帮助页为您提供了详细信息。

linux-gate.so.1是一个虚拟库,它只存在于内核的内存中。它用于执行对内核的系统调用,并根据您的 CPU 找出最有效的方法。这可能是比您的其他 2.6.9 内核机器更晚添加到 Linux 中的。

我不知道 /usr/lib/libcwait.so 是什么,但您可能可以通过执行 rpm -qif /usr/lib/libcwait.so 来获取有关它的一些信息

What does the address given in brackets (for example, (0x002de000)) mean?

It is the (virtual) memory address where the library is loaded.
Recent system can provide randomization of where libraries are loaded though, so
that address might vary between invocations.

shouldn't they be loaded only at runtime?

Yes they are. ldd goes through much of the same procedure as what is
done at runtime though, to be able to figure out various things.

Why does two need any libraries at all?

libc.so.6 is the standard C library (and other stuff, like the interface to the kernel) and is always linked in ny default. gcc has options to control this though, e.g. the -nostdlib flag

ld-linux.so is a the dynamic loader, and is repsonsible for loading/relocating other shared libraryis and run your application. The manpage for ld-linux.so gives you the details.

linux-gate.so.1 is a virtual library, it exists only in memory in the kernel. It's used to perform system calls to the kernel, and figures out the most efficient way to do so based on your CPU. This was probably added to linux later than your other 2.6.9 kernel machine.

I don't know what /usr/lib/libcwait.so is , but chances are you can get some info about it by doing rpm -qif /usr/lib/libcwait.so

假装爱人 2024-10-04 01:03:17

地址基本上是随机数。在设计安全实现之前,ldd 将一致地指示加载程序部分的内存地址。大约五年前以来,许多版本的 Linux 现在故意随机化加载地址,以挫败潜在的病毒编写者等。我编译了 one.c (作为 tc)并重复执行 ldd:

[wally@zenetfedora .bin]$ cat t.c
#include <stdio.h>
int main()
{
    printf ("%d", 45);
}
[wally@zenetfedora .bin]$ gcc -o t t.c -O3
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x009e5000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00b8d000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00238000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x002a0000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00f93000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00c7a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d1a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d12000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)

crtl 和 ld -linux加载地址是一致的,但是linux-gate是随机的。

需要库是因为需要运行 C 运行时初始化和终止。当然,这些在很大程度上可以被优化,因为 stdin、stdout、stderr 等不需要初始化。尽管如此,crtl 仍然是 main() 被调用的方式。

不同风格和版本的 Linux 有差异。 Glib 的演变经历了许多曲折。有些东西已移至其他图书馆。这与当地杂货店搬运物品的原因几乎是一样的。没有多大意义。

The addresses are basically random numbers. Before secure implementations were devised, ldd would consistently indicate the memory addresses where the program sections were loaded. Since about five years ago, many flavors of Linux now intentionally randomize load addresses to frustrate would-be virus writers, etc. I compiled one.c (as t.c) and repeatedly executed ldd:

[wally@zenetfedora .bin]$ cat t.c
#include <stdio.h>
int main()
{
    printf ("%d", 45);
}
[wally@zenetfedora .bin]$ gcc -o t t.c -O3
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x009e5000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00b8d000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00238000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x002a0000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00f93000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00c7a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d1a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d12000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)

The crtl and ld-linux load addresses are consistent, but linux-gate is randomized.

Libraries are needed because the C run time initialization and termination needs to run. Granted, those could largely be optimized away since stdin, stdout, stderr, etc., etc. don't need to be initialized. Still, the crtl is how main() gets called.

Different flavors and versions of Linux have differences. The evolution of glib has had many twists and turns. Some stuff has been moved to other libraries. It's pretty much the same thing as why your local grocery store moves things around. It doesn't have much meaning.

反目相谮 2024-10-04 01:03:17

该数字是运行可执行文件时加载库的内存地址。它是在链接时确定的,并且通常是随机的,以使库函数地址不可预测,从而更难以在漏洞利用中使用。 GCC 默认链接标准 C 库。 libcwait 可能是另一个默认库,可能由较旧的 GCC 版本使用。

The number is the memory address where the library is loaded when the executable is run. It is determined at link time and is usually randomized in order to make library function addresses unpredictable and thus more difficult to use in exploits. The standard C library is linked by default by GCC. libcwait is probably another default library, possibly used by older GCC versions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文