Call a function in another object file without using PLT within a shared library?
Asked Answered
C

2

3

I have two assembly codes, code1.s and code2.s and I want to build a relocatable (using -fPIC switch) shared library from these two.

I want code2.s call a function, named myfun1, which is defined in code1.s.

When I use call myfun1@PLT in code2.s it finds the function and it works like a charm but it uses PLT section to call this function which is in the same shared library. I want to do this without adhering to PLT section. When I remove @PLT I get the relocation R_X86_64_PC32 against symbol error for myfun1.

How can I do this without using PLT section? Is there any way at all? I think it should be feasible as the shared library should be relocatable but not necessary each of its object files, therefore why calling a function inside the same library should goes through the PLT section.

Here is my compile commands:

For codeX.s:

gcc -c codeX.s -fPIC -DPIC -o codeX.o

or

gcc -c codeX.s -o codeX.o

and for sharelibrary named libcodes.so:

gcc -shared -fPIC -DPIC -o libcodes.so code1.o code2.o

Just as you may be curious why I am doing so, I have many object files and each of them wants to call myfun1. Here I just made it simpler to ask the technical part. Even I tries to put myfun1 in all codeX.s files but I get the error that myfun1 is defined multiple times. I don't that much care about space and if I get to put myfun1 in all files.

Camp answered 28/7, 2018 at 17:38 Comment(3)
If myfun1 is defined in same shared object (shared library) as the call myfun1 instruction, it should work.Powel
Yes that it is true. I actually forget to say in my case I have many object files and they all want to call myfun1. In my question I did not give why I am doing this and just asked the technical part. I edited my question.Camp
Actually, I'm wrong. Because of ELF semantics you can't reference global functions defined in the same shared object except through the PLT because ELF lets other images override the symbol. Technically there's no reason why you can't just call the function directly and not still end up with a relocatable shared object, but the GNU linker enforces the ELF semantics. You can work around this problem by changing the visibility of the symbol to hidden, but then it can't be accessed outside of the shared object.Powel
W
4

From within one source file you can just use two labels (Building .so with recursive function in it), one with .globl and the other not. But that's not sufficient across source files within the shared library.

Still useful in combination with the below answer for functions that are also exported: one .hidden and one not, so you can efficiently call within the library.


Use .globl and .hidden to create a symbol that can be seen outside the current object file, but not outside the shared library. Thus it's not subject to symbol-interposition, and calls from other files in the same shared library can call it directly, not through the PLT or GOT.

Tested and working example:

## foo.S
.globl myfunc
.hidden myfunc
myfunc:
   #.globl myfunc_external    # optional, a non-hidden symbol at the same addr
   #myfunc_external:
    ret

## bar.S
.globl bar
bar:
    call myfunc
    ret

Build with gcc -shared foo.S bar.S -o foo.so, and objdump -drwC -Mintel foo.so:

Disassembly of section .text:

000000000000024d <myfunc>:
 24d:   c3                      ret    

000000000000024e <bar>:
 24e:   e8 fa ff ff ff          call   24d <myfunc>     # a direct near call
 253:   c3                      ret    

(I actually built with -nostdlib as well to keep the disassembly output clean for example purposes by omitting the other functions like __do_global_dtors_aux and register_tm_clones, and the .init section.)


I think Glibc uses strong or weak_alias for this (what does the weak_alias function do and where is it defined), so calls from within the shared library can use the normal name. Where are syscalls located in glibc source, e.g. __chdir and chdir.

e.g. glibc's printf.c defines __printf and makes printf a strong alias for it.

io/chdir.c defines __chdir and makes chdir a weak alias for it.

One of the x86-64 memchr asm implementations also uses a strong_alias macro (at the bottom of the file).


The relevant GAS directives are:

There's no strong alias GAS directive. That may be equivalent to simply foo = foo_internal or an equivalent .set foo, foo_internal.

(TODO: complete example and more details of what strong/weak do exactly. I don't currently know, so edits welcome if I don't get around to reading the docs myself. I know this stuff exists and solves this problem, but I don't know exactly how.)

Washwoman answered 28/7, 2018 at 18:38 Comment(2)
Actually I do not care myfun1 to be visible externally. I just want all codes in that library to see that and use it without adhering to PLT.Camp
@masec: .hidden solves the problem. Updated my answer with an example that links on my computer.Washwoman
C
0

Well, I was not able to find any way to do so but as I edited my question I do not care to put myfun1 in all object files.

The problem I had was that linker outputted error that I have defined myfun1 in multiple places and that was all because I had globl directive for myfun1 which when I removed that line it get fixed.

Thanks Ross Ridge for pushing me again to try that.

Camp answered 28/7, 2018 at 18:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.