是否可以仅使用as和ld创建共享对象?

时间:2019-04-14 10:21:28

标签: shared-libraries ld gas

我无法找到足够的信息来使用as和ld在程序集中创建共享对象。

我想创建一个共享库,其中包含一些带有变量的函数(.data节)。但是当我的代码中有一个.data段时,ld将不接受-shared选项。 (在创建共享库时,不能将R_X86_64_32S相对于'.data'的重定位;使用-fPIC重新编译)。当然可以在共享对象代码中使用局部变量,但是如果不使用-fPIC选项编译C代码,我将找不到有关如何执行此操作的信息。

my_lib.s:

.globl print_info

.data
    output:
        .ascii "The processor vendor ID is 'xxxxxxxxxxxx'\n"

.bss

.text
    print_info:
        xor %eax, %eax
        cpuid
        movq $output, %rdi
        movl %ebx, 28(%rdi)
        movl %edx, 32(%rdi)
        movl %ecx, 36(%rdi)
        movl $1, %eax
        movl $1, %edi
        movq $output, %rsi
        movl $42, %edx
        ret
caller.s:

.globl _start

.data

.bss

.text
    _start:
        # some code to load shared library
        # with open() and mmap() syscalls

        subq $8, %rsp         # align stack
        call print_info
        addq $8, %rsp

        # some code here

        movl $60, %eax        # exit program
        xor %edi, %edi
        syscall
as my_lib.s -omy_lib.o
as caller.s -ocaller.o

不产生任何错误。但是

ld -shared my_lib.o

礼物:

ld: my_lib.o: relocation R_X86_64_32S against `.data' can not be used when making a shared object; recompile with -fPIC
ld: final link failed: nonrepresentable section on output

我已经找到的关于该主题的所有信息,都使用C代码和gcc进行编译和链接。任何人都可以演示如何在不使用C进行编码和使用gcc的情况下进行操作吗?

2 个答案:

答案 0 :(得分:0)

您的程序集与位置无关。特别是:

movq $output, %rdi

应该成为

movq $output(%rip), %rdi

一般来讲,我建议使用C语言(用-fPIC编译等效代码,然后检查生成的asm以获取必要的语法。

答案 1 :(得分:0)

如上所述,必须使用与位置无关的代码编写共享库。使用libdl.so从库中动态加载函数[使用open()和mmap()系统调用必须在以后出现],我可以全部使用:

lib.s: 

.globl print_info

.data
    output:
        .ascii "The processor vendor ID is 'xxxxxxxxxxxx'\n"

.bss

.text
    print_info:
        xor %eax, %eax
        cpuid
        leaq output(%rip), %rdi
        movl %ebx, 28(%rdi)
        movl %edx, 32(%rdi)
        movl %ecx, 36(%rdi)
        movl $1, %eax
        movl $1, %edi
        leaq output(%rip), %rsi
        movl $42, %edx
        syscall
        ret
assemble and link with:

as -olib.o lib.s
ld -shared -olib.so lib.o
rm lib.o
caller.s:

.globl _start

.data
    so_name:
        .asciz "./lib.so"
    func_name:
        .asciz "print_info"

.bss
    .lcomm handle, 8
    .lcomm func, 8

.text
    _start:
        movq $so_name, %rdi
        movl $1, %esi        # RTLD_LAZY == 1
        call dlopen

        movq %rax, handle
        movq %rax, %rdi
        movq $func_name, %rsi
        call dlsym

        movq %rax, func      # Not really necessary here, as func is used
                             # immediately and just this once
        call *%rax

        movq handle, %rdi
        call dlclose

        movl $60, %eax
        xorl %edi, %edi
        syscall
assemble and link with:

as -ocaller.o caller.s
ld -dynamic-linker /usr/lib64/ld-linux-x86-64.so.2 -ocaller caller.o -ldl
rm caller.o

现在,您可以使用以下命令运行呼叫者:

./caller

使用_start作为条目时,堆栈似乎已正确对齐(与使用main相对,这显然会在调用main =您的程序之前通过按%rbp引起初始未对齐),因此无需进行调整

subq $8, %rsp

通话前和

addq $8, %rsp

之后。至少看起来是这样,但在这一点上我可能是错的。