【问题标题】:Is it possible to create a shared object using only as and ld?是否可以仅使用 as 和 ld 创建共享对象?
【发布时间】:2019-04-14 10:21:27
【问题描述】:

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

我想创建一个共享库,其中包含一些带变量的函数(.data 部分)。但是当我的代码中有一个 .data 段时, ld 不会接受 -shared 选项。 (在制作共享对象时,不能使用针对 '.data' 的重定位 R_X86_64_32S;使用 -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 的情况下进行操作吗?

【问题讨论】:

    标签: shared-libraries ld gnu-assembler


    【解决方案1】:

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

    movq $output, %rdi
    

    应该变成

    movq $output(%rip), %rdi
    

    作为一般方法,我建议用 C 编译等效代码(使用 -fPIC),然后检查生成的 asm 是否有必要的语法。

    【讨论】:

      【解决方案2】:

      正如上面提到的yugr,共享对象必须用与位置无关的代码来编写。使用 libdl.so 从 lib 中动态加载函数 [使用 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
      

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

      【讨论】:

        猜你喜欢
        • 2016-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多