Во-первых, позвольте мне начать с того, что это действительно XY проблема .
Моя идея состоит в том, чтобы скомпилировать и выгрузить сборку из библиотеки string.h в c. Затем я скопировал и вставил выгруженную сборку в мою программу.
Вы должны , а не сделать это. Стандартная библиотека имеет очень тщательно оптимизированные функции, которые необходимо обрабатывать с осторожностью и которые очень , очень сложны. Другими словами, они в основном бесполезны в образовательных целях, если вы изучаете ассемблер.
Вам просто нужно написать свою любимую реализацию в C и затем скомпилировать ее.
* 1021 Файл заголовка (такой как
string.h
) обычно
не содержит определения функций. Он содержит только их декларацию. Реальные функции на самом деле
уже скомпилированы в динамический c объект библиотеки, который установлен в вашей системе (то есть в самой библиотеке).
Когда вы компилируете программу, компилятор автоматически связывает его со стандартной библиотекой C. Согласно этого ответа , в OS X стандартная библиотека должна находиться в /usr/lib/libSystem.B.dylib
. В Ubuntu обычно это /lib/x86_64-linux-gnu/libc.so.6
. Следующее относится к обеим платформам без проблем.
Если вы хотите взглянуть на разборку конкретной функции библиотеки, вы можете запустить objdump
в библиотеке, передав ее в less
, а затем выполнить поиск для имени функции:
$ objdump -d /usr/lib/libSystem.B.dylib | less
Находясь внутри less
, вы можете выполнить поиск, набрав /
, а затем имя функции, а затем нажмите Введите и используйте n или N для навигации по совпадениям.
Кроме того, вы можете вывести вывод objdump
в файл и проверить его с помощью текстового редактора:
$ objdump -d /usr/lib/libSystem.B.dylib > libSystem.disasm
Проблема, связанная с такими вещами, заключается в том, что в стандартной библиотеке есть много разных и более сложных имен для стандартных функций, чем те, которые вы видите в string.h
. Внутри используются разные символы. Например, в Linux при использовании printf
соответствующий символ в lib c фактически равен __printf
. См. здесь , например.
Вы можете найти реальное имя символа стандартной библиотечной функции, скомпилировав программу, которая ее использует, и просмотрев разобранный код, например:
#include <string.h>
#include <stdio.h>
int main(void) {
char s[100];
scanf("%99s", s);
size_t len = strlen(s);
return 0;
}
Затем выполните:
$ gcc prog.c
$ objdump -d a.out
...
0000000000000720 <main>:
720: 55 push %rbp
721: 48 89 e5 mov %rsp,%rbp
724: 48 83 ec 70 sub $0x70,%rsp
728: 48 8d 45 90 lea -0x70(%rbp),%rax
72c: 48 89 c6 mov %rax,%rsi
72f: 48 8d 3d ae 00 00 00 lea 0xae(%rip),%rdi # 7e4 <_IO_stdin_used+0x4>
736: b8 00 00 00 00 mov $0x0,%eax
73b: e8 90 fe ff ff callq 5d0 <__isoc99_scanf@plt>
740: 48 8d 45 90 lea -0x70(%rbp),%rax
744: 48 89 c7 mov %rax,%rdi
747: e8 74 fe ff ff callq 5c0 <strlen@plt>
74c: 48 89 45 f8 mov %rax,-0x8(%rbp)
750: b8 00 00 00 00 mov $0x0,%eax
755: c9 leaveq
756: c3 retq
757: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
75e: 00 00
И вы можете видеть, что в моем случае scanf
на самом деле __isoc99_scanf
, в то время как strlen
не изменяется.
Затем я могу посмотреть разборку strlen
, которая на Моя система (Ubuntu) выглядит следующим образом:
$ objdump -d /lib/x86_64-linux-gnu/libc.so.6 | less
...
0000000000080650 <strlen@@GLIBC_2.2.5>:
80650: 66 0f ef c0 pxor %xmm0,%xmm0
80654: 66 0f ef c9 pxor %xmm1,%xmm1
80658: 66 0f ef d2 pxor %xmm2,%xmm2
8065c: 66 0f ef db pxor %xmm3,%xmm3
80660: 48 89 f8 mov %rdi,%rax
80663: 48 89 f9 mov %rdi,%rcx
80666: 48 81 e1 ff 0f 00 00 and $0xfff,%rcx
8066d: 48 81 f9 cf 0f 00 00 cmp $0xfcf,%rcx
80674: 77 6a ja 806e0 <strlen@@GLIBC_2.2.5+0x90>
80676: f3 0f 6f 20 movdqu (%rax),%xmm4
8067a: 66 0f 74 e0 pcmpeqb %xmm0,%xmm4
8067e: 66 0f d7 d4 pmovmskb %xmm4,%edx
80682: 85 d2 test %edx,%edx
80684: 74 04 je 8068a <strlen@@GLIBC_2.2.5+0x3a>
80686: 0f bc c2 bsf %edx,%eax
80689: c3 retq
8068a: 48 83 e0 f0 and $0xfffffffffffffff0,%rax
8068e: 66 0f 74 48 10 pcmpeqb 0x10(%rax),%xmm1
80693: 66 0f 74 50 20 pcmpeqb 0x20(%rax),%xmm2
80698: 66 0f 74 58 30 pcmpeqb 0x30(%rax),%xmm3
8069d: 66 0f d7 d1 pmovmskb %xmm1,%edx
806a1: 66 44 0f d7 c2 pmovmskb %xmm2,%r8d
806a6: 66 0f d7 cb pmovmskb %xmm3,%ecx
806aa: 48 c1 e2 10 shl $0x10,%rdx
...
...
Как видите, даже такая простая функция на самом деле кажется невозможной для понимания в джунглях сложных инструкций из-за многочисленных оптимизаций и ручной настройки, применяемых авторы glib c по годам.