在 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 回答。这让我很困惑,我想避免每次都修补二进制文件。
我目前正在学习使用 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
另外如前所述,如果有人知道为什么它会自动将 libc 指定为运行时,我将非常感激,如果他们愿意 post 回答。这让我很困惑,我想避免每次都修补二进制文件。