在Linux上加载C运行时

时间:2017-01-27 21:07:06

标签: c linux windows assembly dll

作为Linux上的新手,我有一些问题:
如何从程序加载C运行时? 路径和文件名是什么?

在Windows上

C:\Windows\System32\msvcrt.dll

顺便问一下,Linux上调用的DLL是什么?

与MS LoadLibraryGetProcAddress对应的功能有哪些?
它们驻留在什么DLL中? 我必须链接哪个图书馆才能访问它们? 在Windows下,它是kernel32.libkernel32.dll

最后:如何编写独立于目标平台的Masm / JWasm代码?
是否有反映命令行上使用的目标arg的汇编符号?

编辑:我忘了问几个问题:Linux是64位还是32位?它是否使用与64位MS C相同的调用约定?我的意思是rcx,rdx,r8,r9等参数。

4 个答案:

答案 0 :(得分:6)

典型的类UNIX系统将ELF文件格式用于目标文件,共享库和二进制文件。许多东西与Windows类似,但有些是不同的。首先,这是一个常用后缀列表:

UNIX    Windows
*.o     *.obj   object file 
*.a     *.lib   static library
*.so    *.dll   shared object (ELF targets)
*.dylib *.dll   shared object (Mach O targets, i.e. Mac OS X)
*       *.exe   binary (no suffix on UNIX)

静态链接的工作方式与Windows上的相同,但动态链接不同。首先,共享库没有lib文件。相反,静态链接器ld为您希望直接调用共享对象时调用的每个函数生成一个适当的PLT(过程链接表)和存根。在此使用方案中,您链接到的共享对象存储在二进制文件的特殊部分中。您的二进制文件不是直接执行的,而是将动态加载程序ld.so作为二进制文件的解释器加载,查找所有需要的共享对象并将它们加载到地址空间中。符号引用在第一次调用时解析(除非您另行指定)。

您还可以使用dl库在运行时加载共享对象,该库提供函数dlopendlclosedlsymdlerror以加载共享对象和访问符号。请注意,dl库可能取决于可用的libc部分,因为所有系统调用都是通过libc完成的。在某些类UNIX操作系统上,libdl已集成到libc中。

您当然也可以手动加载共享对象,但这样做很复杂。

没有直接相当于Microsoft的kernel32.dll。系统调用在C标准库libc.so中实现(也可以静态地用作libc.a),但您也可以直接调用操作系统。装配系统调用接口的稳定性因操作系统而异,但libc接口是稳定的。我强烈建议您使用libc专门调用操作系统。

CRT包含libc和几个目标文件,当您通过C编译器链接时,这些目标文件链接到您的程序中。这些目标文件从堆栈中检索参数向量和ELF辅助向量,并调用libc。然后libc为您调用main。我强烈建议您始终链接C编译器,并使汇编程序从main开始。这样可以实现更轻松,更便携的编程。

如需进一步阅读,我建议您阅读SysV ABI和ELF格式的文档。

如果你想使用libc,我建议你链接C编译器:

cc -o binary object1.o object2.o ... -llibrary1 -llibrary2 ...

这也将CRT条目存根链接到您的程序中;程序本身应该提供一个名为main的全局符号,它由ABI调用约定中的libc调用(在i386上,cdecl用于所有函数,在amd64上使用SysV ABI调用约定) 。签名如下:

main(argc, argv, envp);

其中argc是命令行参数的数量,argv是指向命令行参数的以null结尾的指针数组的指针,而envp是指向以null结尾的环境变量数组的指针(每个entry的格式为key=value。如果main返回,则C运行时调用exit函数,返回值为main作为退出状态。注意{{1}刷新所有stdio缓冲区,这样你就不必这样做了。

您还可以使用exit选项创建静态二进制文件:

-static

请注意,某些libc功能(例如DNS查找)需要动态加载共享库,如果您使用这些功能中的任何一个,则在执行程序期间可能会打开共享库。

如果您不想使用libc,请将程序与cc -static -o binary object1.o object2.o ... -llibrary1 -llibrary2 ... 链接器链接:

ld

在这种情况下,程序的入口点是一个名为ld -o binary object1.o ... -llibrary1 ... 的全局符号,操作系统在启动时会在堆栈上放置一堆有用的东西,请阅读上述ABI文档以获取详细信息。

_startstdinstdout分别可用作文件描述符0,1和2。不保证它们是开放的。您可以使用标准POSIX函数stderrread()来读取和写入数据。访问指向C write()结构FILEstdinstdout的指针取决于您为其编程的操作系统。在Linux上,这些只是外部符号,但在其他系统(例如FreeBSD)上,您可能需要调用函数来获取指针。

答案 1 :(得分:1)

  

如何从程序加载C运行时?

通常在调用main之前很久就会将C运行时加载到程序映像中。实际上它是正在进行main调用的运行时。顺便说一下,它也就像在Windows中一样;具有轻微的特性,Windows程序可以WinMain而不是main

但是,如果您打算在C运行时内找到符号地址,那么您可以dlopen代替GetModuleHandleLoadLibrary

  

在Windows上C:\Windows\System32\msvcrt.dll

实际上它是%SYSPATH%\msvcrt.dll,但是在旁边挑剔......

在* nix-systems上(通常)/lib/libc.so

  

顺便问一下,Linux上调用的DLL是什么?

共享对象。因此文件后缀为.so - 或者更确切地说是.so.$VERSION,例如libsomething.so.1.2

关于共享对象的强制性阅读:https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf

  

MS LoadLibrary和GetProcAddress对应的功能是什么?

dlopendlsym

  

它们驻留在什么DLL中?

它们位于libdl.so

  

我必须链接哪个库才能访问它们?

libdl.so

答案 2 :(得分:1)

我找到了这些不错的解决方案,没有我自己的发明:

;--- "hello world" for Linux which uses int 80h.
;--- assemble: jwasm -Fo=Linux1.o Linux1.asm
;--- link:     jwlink format ELF runtime linux file Linux1.o name Linux1

    .386
    .model flat

stdout    equ 1
SYS_EXIT  equ 1
SYS_WRITE equ 4

    .data

string  db 10,"Hello, world!",10

    .code

_start:

    mov ecx, offset string
    mov edx, sizeof string
    mov ebx, stdout
    mov eax, SYS_WRITE
    int 80h
    mov eax, SYS_EXIT
    int 80h

    end _start

啊,那太好了。这一个:

;--- "hello world" for 64-bit Linux, using SYSCALL.
;--- assemble: JWasm -elf64 -Fo=Lin64_1.o Lin64_1.asm
;--- link:     gcc Lin64_1.o -o Lin64_1

stdout    equ 1
SYS_WRITE equ 1
SYS_EXIT  equ 60

    .data

string  db 10,"Hello, world!",10

    .code

_start:
    mov edx, sizeof string
    mov rsi, offset string
    mov edi, stdout
    mov eax, SYS_WRITE
    syscall
    mov eax, SYS_EXIT
    syscall

    end _start

辉煌!这就是我在寻找的东西。低级别的东西。第一个就像旧的MSDOS和Linux系统的int 80h接口一样。另一个使用syscall指令。

这很简单!在Windows中没有任何类似的东西。似乎asm progr在Linux下比赢得更容易。然而,这提出了一些问题:

syscall instr仅在64位Linux下可用吗?

通过syscall / int 80h可以获得系统例程吗?它们丰富吗?你能没有clib.so吗?

上述其他人的贡献虽然很有价值,但显然是C程序员的工作。我更像是在asm工作的Linux bit黑客。

特别是,是否有系统调用加载SO并查询功能地址?

答案 3 :(得分:0)

  

MS LoadLibrary和GetProcAddress对应的功能是什么?

分别为

dlopendlsym

  

它们驻留在什么DLL中?

通常libdl。在链接器命令行中使用-ldl来附加它。