Compiling a shared library out of golang project on AIX 7.2 through static archive detour

Environment:

  • AIX 7.2
  • gcc version 8.3.0
  • go version go1.16.12 aix/ppc64

Hello everyone,
I am currently trying to develop a new component using golang to replace unmaintainable C++ code on our AIX 7.2 platform.

We need to create a shared library that can be used by applications written in other languages such as Perl or Python.
I am aware that go’s latest release 1.16 on AIX 7.2 does not support -buildmode=c-shared, however I’m currently investigating whether it is possible in some other way to circumvent this limitation by using a c-archive and link that into a shared object using gcc.

So far I have created a small example project sharedLibTest.go

package main

import (
	"fmt"
)

import "C"

func main() {
	fmt.Printf("%s\n", "Golang: main was called")
	MyPackage_Init()
	MyPackage_Create()
}

//export MyPackage_Init
func MyPackage_Init() {
	fmt.Printf("%s\n", "Golang: MyPackage_Init was called")
}

//export MyPackage_Create
func MyPackage_Create() {
	fmt.Printf("%s\n", "Golang: MyPackage_Create was called")
}

It should be used by a simplistic main.c

#include <stdio.h>
#include "sharedLibTest.h"

int main() {
    printf("%s\n", "C: main() called");
    MyPackage_Init();
    MyPackage_Create();
}

I am able to compile the above .go code with

go build -v -buildmode=c-archive -mod vendor -o /home/myuser/workspace/go_proj/sharedLibTest/sharedLibTest.a /home/myuser/workspace/go_proj/sharedLibTest/sharedLibTest.go

Because of AIX specific weird behaviour I need to prepare a list of symbols that should be exported for the linking

$ cat > symbols.export << EOF
> MyPackage_Init
> MyPackage_Create
> EOF

With that I can use gcc to create a shared object out of my static compilation

gcc -g -O2 -mcpu=power7 -maix64 -shared -lpthread -Wl,-bE:symbols.export -o libsharedLibTest.so -Wl,-bnoobjreorder ./sharedLibTest.a

Now, again because of how weird AIX behaves, we need to add the shared object to an archive, as the AIX version of a linker does not look for .so files, but only .a files.

ar -X64 rcs libsharedLibTest.a libsharedLibTest.so

Finally I can try to link my main.c against the dynamic library with

gcc -L. -g -O2 -mcpu=power7 -maix64 -Wl,-bnoobjreorder -lsharedLibTest -lpthreads main.c 

That also compiles successfully, however when I try to run my application with

LD_LIBRARY_PATH=/home/myuser/workspace/go_proj/sharedLibTest ./a.out

I get the error

$ ./a.out 
exec(): 0509-036 Cannot load program ./a.out because of the following errors:
        0509-150   Dependent module /home/myuser/workspace/go_proj/sharedLibTest/libsharedLibTest.a(libsharedLibTest.so) could not be loaded.
        0509-187 The local-exec model was used for thread-local
                   storage, but the module is not the main program.
        0509-193 Examine the .loader section header with the
                 'dump -Hv' command.

My understanding is, that the c-archive created by go build is not compiled using whatever equivalent of gcc’s -fPIC option to create Position Independenct Code (PIC). So far i have been unable to pass any equivalent of that to the go build invocations, and adding -gcflags="-shared" leads to an error along the lines of this

$  go build -buildmode=c-archive -gcflags=-shared -ldflags=-linkmode=external -mod vendor -o sharedLibTest.a sharedLibTest.go                                                                                      <
# command-line-arguments
main.main: unknown reloc to .TOC.: 48 (R_ADDRPOWER_PCREL)
_cgoexp_87081e778e87_MyPackage_Init: unknown reloc to .TOC.: 48 (R_ADDRPOWER_PCREL)
_cgoexp_87081e778e87_MyPackage_Create: unknown reloc to .TOC.: 48 (R_ADDRPOWER_PCREL)

I got the hint to try out gccgo, which might allow me to pass -fPIC to the compilation proper. I haven’t tried that yet because for one I’m currently awaiting the installation of that package on our AIX dev machine by the admins, but I also got to admit that I’m currently unclear how to use gccgo so that i get a dynamic lib out of that in the same nice way that go build did with the apparent implicit invocation of cgo.
Using plain gccgo seems to just compiles it down to an object file but doesn’t support the meta package ´import "C"´. Would I need to manually create the header file then?

All in all the question I have is: Has anyone been able to successfully create a shared object out of a go project for AIX (7.2 on PowerPC BigEndian)?

Even though it is a rather complicated affair I am still hoping that there is some way around this current toolchain limitation and that we don’t have to resort to using a different language or abandon the shared object approach entirely.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.