在 32 位汇编中编写和链接共享库

Writing and linking shared libraries in assembly 32-bit

我目前正在学习使用 att 语法的 x86 汇编程序。在过去的时间里,我已经编写了没有依赖项的练习程序。现在我想尝试编写一个共享的共享库,因为这是我大部分时间在 C 中所做的。

我认为编写一个简单的“测试”程序可能是个好主意,该程序由一个用 asm 编写的测试库和一个程序组成,该程序 link 用于此测试库.

我组装了库:as -32 prog.s -o prog.o
和来电者:as -32 startprog.s -o startprog.o

在我组装了两个文件之后,我 运行 图书馆的 linker ld -melf_i386 -fPIE -shared prog.o -o libprog.so
和来电者 ld -melf_i386 startprog.o -L./ -lprog -o startprog

到目前为止一切正常。但是后来我尝试 运行 程序 ./startprog,这导致了段冲突。我用 gdb 重新 运行 并设置 _start 作为断点。当我在 gdb 中输入 r 以实际开始执行时, 我收到了相同的 SIGSEGV。它似乎发生在 libc write() 功能。至少那是我能做的。

完整的输出如下所示:

[cediw@cwm10 pC $] gdb ./startprog 
Reading symbols from ./startprog...
(No debugging symbols found in ./startprog)
(gdb) b _start 
Breakpoint 1 at 0x8049020
(gdb) r
Starting program: /home/cediw/dev/asm/re/pC/startprog 
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.

Program received signal SIGSEGV, Segmentation fault.
0xf7f06fe1 in write () from /usr/lib/libc.so.1
(gdb) disas
Dump of assembler code for function write:
   0xf7f06fd0 <+0>: push   %esi
   0xf7f06fd1 <+1>: push   %ebx
   0xf7f06fd2 <+2>: sub    [=10=]x14,%esp
   0xf7f06fd5 <+5>: mov    0x20(%esp),%ebx
   0xf7f06fd9 <+9>: mov    0x24(%esp),%ecx
   0xf7f06fdd <+13>:    mov    0x28(%esp),%edx
=> 0xf7f06fe1 <+17>:    mov    %gs:0xc,%eax
   0xf7f06fe7 <+23>:    test   %eax,%eax
   0xf7f06fe9 <+25>:    jne    0xf7f07010 <write+64>
   0xf7f06feb <+27>:    mov    [=10=]x4,%eax
(gdb) i r
eax            0xf7fa44e0          -134593312
ecx            0xf7fa44e0          -134593312
edx            0x1aa               426
ebx            0x1                 1
esp            0xffffd3f4          0xffffd3f4
ebp            0x0                 0x0
esi            0x0                 0
edi            0x0                 0
eip            0xf7f06fe1          0xf7f06fe1 <write+17>
eflags         0x10282             [ SF IF RF ]
cs             0x23                35
ss             0x2b                43
ds             0x2b                43
es             0x2b                43
fs             0x0                 0
gs             0x0                 0

我的测试库是这样的:

# file: prog.s
.section .rodata    
    str: .string "Hallo Welt\n"
    
.section .text
    .globl  test
    .type   test, @function

.macro push_all
    push    %ebx
    push    %ecx
    push    %edx
    push    %edi
    push    %esi
.endm

.macro pop_all
    pop %esi
    pop %edi
    pop %edx
    pop %ecx
    pop %ebx
.endm


test:
    push    %ebp
    movl    %esp, %ebp
    push_all

    movl    %esp, %eax
    addl    $_GLOBAL_OFFSET_TABLE_, %eax
    movl    str@GOTOFF(%eax), %ecx

    movl    , %eax
    movl    , %ebx
    movl    , %edx
    int [=11=]x80
    
    pop_all
    pop %ebp
    ret
    .size   test, .-test

#startprog.s
.section .text
    .globl _start
    .globl test

_start:
    call    test

我到底做错了什么?有什么资源可以让我稍微了解一下吗 更好的?因为目前我正在抓取 google 来寻找这方面的好资源。

感谢和问候 塞德里克

编辑:objdump

[cediw@cwm10 pC $] objdump -d -Matt -s startprog

startprog:     file format elf32-i386

Contents of section .interp:
 8048134 2f757372 2f6c6962 2f6c6962 632e736f  /usr/lib/libc.so
 8048144 2e3100                               .1.             
Contents of section .hash:
 8048148 01000000 02000000 01000000 00000000  ................
 8048158 00000000                             ....            
Contents of section .gnu.hash:
 804815c 01000000 01000000 01000000 00000000  ................
 804816c 00000000 00000000                    ........        
Contents of section .dynsym:
 8048174 00000000 00000000 00000000 00000000  ................
 8048184 01000000 00000000 00000000 12000000  ................
Contents of section .dynstr:
 8048194 00746573 74006c69 6270726f 672e736f  .test.libprog.so
 80481a4 00                                   .               
Contents of section .rel.plt:
 80481a8 0cb00408 07010000                    ........        
Contents of section .plt:
 8049000 ff3504b0 0408ff25 08b00408 00000000  .5.....%........
 8049010 ff250cb0 04086800 000000e9 e0ffffff  .%....h.........
Contents of section .text:
 8049020 e8ebffff ff                          .....           
Contents of section .dynamic:
 804af70 01000000 06000000 04000000 48810408  ............H...
 804af80 f5feff6f 5c810408 05000000 94810408  ...o\...........
 804af90 06000000 74810408 0a000000 11000000  ....t...........
 804afa0 0b000000 10000000 15000000 00000000  ................
 804afb0 03000000 00b00408 02000000 08000000  ................
 804afc0 14000000 11000000 17000000 a8810408  ................
 804afd0 00000000 00000000 00000000 00000000  ................
 804afe0 00000000 00000000 00000000 00000000  ................
 804aff0 00000000 00000000 00000000 00000000  ................
Contents of section .got.plt:
 804b000 70af0408 00000000 00000000 16900408  p...............

Disassembly of section .plt:

08049000 <.plt>:
 8049000:   ff 35 04 b0 04 08       pushl  0x804b004
 8049006:   ff 25 08 b0 04 08       jmp    *0x804b008
 804900c:   00 00                   add    %al,(%eax)
    ...

08049010 <test@plt>:
 8049010:   ff 25 0c b0 04 08       jmp    *0x804b00c
 8049016:   68 00 00 00 00          push   [=13=]x0
 804901b:   e9 e0 ff ff ff          jmp    8049000 <.plt>

Disassembly of section .text:

08049020 <_start>:
 8049020:   e8 eb ff ff ff          call   8049010 <test@plt>

清晰可见 linker links libc,即使我尝试使用 -nostdlib

更新

好的,所以我查看了命令 file startprog 的输出,它告诉我 运行 时间设置为 c。我已经将 patchelf --set-interpreter /lib/ld-linux.so.2 startprog 的 运行 时间更改为 linux 运行 时间,现在可以使用了。我将 post 这作为我问题的答案。但另一个非常重要的问题仍然存在:为什么它甚至 link 它与 c-运行 时间?

UPDATE 中所述,我通过使用 patchelf --set-interpreter /lib/ld-linux.so.2 startprog

修补 ELF 的运行时使其正常工作

另外如前所述,如果有人知道为什么它会自动将 libc 指定为运行时,我将非常感激,如果他们愿意 post 回答。这让我很困惑,我想避免每次都修补二进制文件。