Alex Rivera | Logout

ELF Shared Object in x86-64 Assembly language

Asked 2012-02-18T12:39:29.993
8

I'm trying to create a Shared library (*.so) in ASM and I'm not sure that i do it correct...

My code is:

    .section .data
    .globl var1
var1:
    .quad     0x012345

    .section .text
    .globl func1
func1:
    xor %rax, %rax
  # mov var1, %rcx       # this is commented
    ret

To compile it i run

gcc ker.s -g -fPIC -m64 -o ker.o
gcc ker.o -shared -fPIC -m64 -o libker.so

I can access variable var1 and call func1 with dlopen() and dlsym() from a program in C.

The problem is in variable var1. When i try to access it from func1, i.e. uncomment that line, the compiler generates an error:

/usr/bin/ld: ker.o: relocation R_X86_64_32S against `var1' can not be used when making a shared object; recompile with -fPIC
ker.o: could not read symbols: Bad value
collect2: ld returned 1 exit status

I don't understand. I've already compiled with -fPIC, so what's wrong?

Edit
Report

2 Answers

16

I've already compiled with -fPIC, so what's wrong?

That part of the error message is for people who are linking compiler-generated code.

You're writing asm by hand, so as datenwolf correctly wrote, when writing a shared library in assembly, you have to take care for yourself that the code is position independent.

This means file must not contain any 32-bit absolute addresses (because relocation to an arbitrary 64-bit base is impossible). 64-bit absolute relocations are supported, but normally you should only use that for jump tables.


mov var1, %rcx uses a 32-bit absolute addressing mode. You should normally never do this, even in position-dependent x86-64 code. The normal use-cases for 32-bit absolute addresses are: putting an address into a 64-bit register withmov $var1, %edi (zero-extends into RDI)
and indexing static arrays: mov arr(,%rdx,4), %edx

mov var1(%rip), %rcx uses a RIP-relative 32-bit offset. It's the efficient way to address static data, and compilers always use this even without -fPIE or -fPIC for static/global variables.

You have basically two possibilities:

  • Normal library-private static data, like C compilers will make for __attribute__((visibility("hidden"))) long var1;, same as for -fno-PIC.

    .data
        .globl var1       # linkable from other .o files in the same shared object / library
        .hidden var1      # not visible for *dynamic* linking outside the library
    var1:
        .quad     0x012345
    
    .text
        .globl func1
    func1:
        xor  %eax, %eax             # return 0
        mov  var1(%rip), %rcx   
        ret
    
  • full symbol-interposition-aware code like compilers generate for -fPIC.

    You have to

answered 2012-02-18T14:18:32.363
-1

Ok, i think i found something...

First solution from drhirsch gives almost the same error but the relocation type is changed. And type is always ended with 32. Why is it? Why 64 bit program uses 32-bit relocation?

I found this from googling: http://www.technovelty.org/code/c/relocation-truncated.html

It says:

For code optimisation purposes, the default immediate size to the mov instructions is a 32-bit value

So that's the case. I use 64-bit program but relocation is 32-bit and all i need is to force it to be 64 bit with movabs instruction.

This code is assembling and working (access to var1 from internal function func1 and from external C program via dlsym()):

    .section .data 
    .globl var1 
var1: 
    .quad     0x012345

    .section .text 
    .globl func1 
func1: 
    movabs var1, %rax       # if one is symbol, other must be %rax
    inc %rax
    movabs %rax, var1
    ret

But i'm in doubt about Global Offset Table. Must i use it, or this "direct" access is absolutely correct?

answered 2012-02-19T07:26:58.833

Your Answer