C access symbol in executable (linux) - c

I have an executable binary with many symbols. I am trying to figure out how to access those symbols in my code. dbg can so I know its possible im just not sure how. I cannot create a shared object from it with "gcc -shared -o myexe.so myexe" because there are multiple definitions of the same function
...(.data+0x8e8): first defined here
/usr/bin/ld: warning: Cannot create .eh_frame_hdr section, --eh-frame-hdr ignored.
/usr/bin/ld: error in fipstest(.eh_frame); no .eh_frame_hdr table will be created.
/usr/bin/ld: fipsttest.so: No symbol version section for versioned symbol `NSSUTIL_ArgGetLabel##NSSUTIL_3.14'
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
This means that gcc cannot link to it during compile time with -L because the of the same issue.
the nm command shows all the symbols and the one I want. If I could modify the symbol table to remove all the exports but the ONE I need then it might work but I can't find how to do that. Or if anyone could point me in the right direction to access a binary during runtime and load a function with a physical address that would work too. Any help is appreciated. Thank you.

Related

How can I cross-compile for Solaris with cgo?

I am trying to compile some cgo code for Solaris. I get these errors when I try to build:
$ CGO_LDFLAGS="-L$(pwd)/solaris-11.4-amd64-libs" CGO_CFLAGS='-I/home/shane/src/ioctl-experimentation/solaris-11.4-headers -Wno-unknown-pragmas' CGO_ENABLED=1 GOOS=solaris GOARCH=amd64 go build
# runtime/cgo
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x16): undefined reference to `__libc_csu_fini'
/usr/bin/ld: (.text+0x1d): undefined reference to `__libc_csu_init'
/usr/bin/ld: (.text+0x2a): undefined reference to `__libc_start_main'
/usr/bin/ld: $WORK/b003/_x003.o: in function `_cgo_release_context':
gcc_context.c:(.text+0x5c): undefined reference to `__stack_chk_fail'
/usr/bin/ld: $WORK/b003/_x004.o: in function `x_cgo_sys_thread_create':
gcc_libinit.c:(.text+0x87): undefined reference to `__stack_chk_fail'
/usr/bin/ld: $WORK/b003/_x004.o: in function `_cgo_wait_runtime_init_done':
gcc_libinit.c:(.text+0x121): undefined reference to `__stack_chk_fail'
/usr/bin/ld: $WORK/b003/_x004.o: in function `_cgo_try_pthread_create':
gcc_libinit.c:(.text+0x291): undefined reference to `__stack_chk_fail'
/usr/bin/ld: $WORK/b003/_x006.o: in function `x_cgo_init':
gcc_solaris_amd64.c:(.text+0xb6): undefined reference to `__stack_chk_fail'
/usr/bin/ld: $WORK/b003/_x006.o:gcc_solaris_amd64.c:(.text+0x214): more undefined references to `__stack_chk_fail' follow
collect2: error: ld returned 1 exit status
I am cross-compiling on Linux. Here is my Go version:
$ go version
go version go1.18.3 linux/amd64
The solaris-11.4-amd64-libs directory contains a copy of all files under /lib/amd64 from a Solaris 11.4 AMD64 machine. The solaris-11.4-headers directory contains a copy of all files under /usr/include from a Solaris 11.4 AMD64 machine.
Here is my Go code in main.go:
//go:build solaris
// +build solaris
package main
import "C"
func main() {
}
I know cgo is fully supported for Solaris as of Go 1.5, and I am using Go 1.18.
I'm looking for help understanding why these linker errors are happening, even when I copied across all libs from the /lib/amd64 directory. Is it possible there are more libs I also need to copy over from somewhere else?
Edit
At the suggestion of Liam Kelly, I looked at this question about how to link against a different libc. I tried passing -Xlinker -rpath=$(pwd)/solaris-11.4-amd64-libs as part of CGO_LDFLAGS, but I got the same errors as before. I tried using -nodefaultlibs and -nostdlib both separately and together along with -Xlinker -rpath=$(pwd)/solaris-11.4-amd64-libs, but using either of these two flags either separately or together just increased the number of linker errors.
I am going to assume that libxnet is needed for Solaris and that is why is is being automatically added.
First confirm that the libxnet library is where is should be with sudo find /lib libxnet*. I expect you will see one line of the output show:
lib/64/libxnet.so
Assuming you see the above output, I believe you just need to tell the linker to look in that location with CGO_LDFLAGS="-L/lib/64" CGO_ENABLED=1 GOOS=solaris GOARCH=amd64 go build. If that works then you should be able to embedded that LDFlag in your main.go file with:
// #cgo LDFLAGS: -L/lib/64
import "C"
Once embedded you will not need to explicitly set CGO_LDFLAGS

Seeing where symbols are looked up, during gcc linking?

I have just seen this post: How to tell where the symbols are defined when linking C code ; and tried to run that approach (that is, I tried to look up via -Wl,-trace-symbol=foo during the linking command) on my code, which suffers from undefined reference - but the output is not much different from what is given as an example in that post:
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: ./libfoo.a(foo.o): definition of foo
/usr/bin/ld: ./libfoo.a(foo.o): reference to fputs
/usr/bin/ld: //lib/x86_64-linux-gnu/libc.so.6: definition of fputs
The thing is, I've manually added both -L and -l specifications to my command line, which I expect should pass - but they do not.
So what I am ultimately looking for, is a way to generate a log, that tells me, say:
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: ./libyoo.a(yooA.o): symbol foo looked up, not found
/usr/bin/ld: ./libyoo.a(yooB.o): symbol foo looked up, not found
/usr/bin/ld: ./libfoo.a(foo.o): definition of foo
... which, I hope, will make me understand a bit easier, which include and linker flag directories and files end up being scanned.
Is there a way to generate a log like this?

What happens during a "relocation has invalid symbol index" error?

Here is a test reproducing the problem:
$ echo "void whatever() {}" > prog.c
$ gcc prog.c
This produces the following error on GCC 4.8.4:
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
... etc ...
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Note that on GCC 6.2.0 the errors related to this question disappear, and it instead produces just:
/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
This has been reported a number of times by a number of users, on Stack Overflow, and elsewhere.
I would like to understand this error, not solve it (it is already solved).
This error happens when doing gcc-4.8 prog.c without a main() function inside prog.c.
I have done a text search for this error on the binutils-source package. A tedious googling gave me only one useful link helping me better understanding the concept of relocation handling.
The number of errors does not seem to depend on the program, which suggests the relocations in consideration do not originate in this file, but as a direct result of the missing main() function. I have hypothesized that 3 of these relocations with wrong indexes might be for main(), argc and argv, but many remain, and this is just an unproven hypothesis.
This is quite above my head, and any information that helps me better understand it, or what changed in later versions of GCC, would be warmly welcome.
C Program Features (Unix-like)
every program is compiled separately into elf format
c program can use external variable/function reference, which is linked later
main is not the start of program as you originally thought, c lib has a starter program (crt1.o) which has a _start program which will invoke our main and do cleaning job after main
concludes above statement, we can know that even a very simple program as OP showed need to be linked
ELF Format
ELF has two headers, as following shows:
section header -- used to link multiple elf to make process image
program header -- used to load process image
Here we only focus on section header structure:
mapping<var_name, offset, size...>
// and special cases
mapping<external_var_name, offset, size...>
Every program is compiled separately, which means address allocation is similar (In the early version of linux, every compiled program start with same virtual address -- 0x08000000, and many attacks can make use of this, so it changes to adding some random delta to address to alleviate the problem), so there may exists some overlay area. This is why address relocation needed.
Relocation
The relocation info (offset, value etc) is stored in .rel.* section:
Relocation section '.rel.text' at offset 0x7a4 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000000d 00000e02 R_386_PC32 00000000 main
00000015 00000f02 R_386_PC32 00000000 exit
Relocation section '.rel.debug_info' at offset 0x7b4 contains 43 entries:
Offset Info Type Sym.Value Sym. Name
00000006 00000601 R_386_32 00000000 .debug_abbrev
0000000c 00000901 R_386_32 00000000 .debug_str
When the linker want to set the address of main in the process of relocation, it can't find a symbol in your compiled elf file, so it complains that and stop the linking process.
Example
Here is the simplified version of os implementations, start.c corresponds to crt1.o's source code:
int entry(char *); // corresponds to main
void _start(char *args) {
entry(args);
exit();
}
Ref
ELF
Relocation
Instead of compiling the code directly, go through all the stages of compilation to figure out where the error is arising (as far as I know, such errors occur during linking). Following gcc arguments will be helpful:
-E Preprocess only; do not compile, assemble or link
-S Compile only; do not assemble or link
-c Compile and assemble, but do not link
Now:
gcc -E prog.c
gcc -S prog.c
gcc -c prog.c
With the program/code you have mentioned, all these steps are working perfect with gcc 4.8.4. But, during linking, when you compile using gcc prog.c, the compiler is unable to link with respective library, as it was not mentioned. Also, we have no main function in the prog.c file. So, we need to indicate -nostartfiles switch. Hence, you can compile prog.c as:
gcc prog.c -lc -nostartfiles
This produces the warning:
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000004002a3
This is because of the sequence. i.e., init calls _start function and the _start function calls main function. This warning means that the _start function is unable to locate main function, where the init call is unable to locate _start. Please note that this is just a warning. In order to avoid this warning, we need to change the command to compile without warnings as follows.
gcc prog.c -lc --entry whatever -nostartfiles
With this command, we are instructing the kernel to compile prog.c using gcc by linking the libc.so library with the starting point as the function whatever, where this code contains no main function.
This is the context with gcc 4.8.4, which I've compiled on.
Coming to the case of gcc 6.2.0, I think all these linking stuff is taken care by the compiler itself. Hence, you can simply mention the compiling command as shown below.
gcc -c prog.c -nostartfiles
If it produces any other errors or warnings, you can use the switches mentioned above.
Also, note that crt0 through crtN (N depends on the ELF file) are executed before the init calls _start, which gives the metadata about the memory and other machine dependent parameters. The linking errors shown as
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
do not provide complete information for rectifying the issue, as machines are not as smart as human beings in identifying the point of error.
This produces a complete executable file. Please do notice that such code (without main function) is used when we are working on libraries/modules within a project.
All the data provided is done with step-by-step analysis. You can recreate all the steps mentioned. Hope this cleared your doubt. Good day!
We can break this down into two parts:
Undefined reference to `main'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
This is simply because the C Runtime library (crt1.o) is trying to call your (missing) main() function. There is a good overview of the various C Runtime files here / here.
Relocation X has invalid symbol index Y
Note: This has been a bit of mission (learning opportunity) for me - I've taken a few days to research and understand in the limited free time that I have. It's something that I've wondered about for a long time but never looked into... Hopefully my understanding is correct (though clearly not complete - I'll update it if I can).
This is a little more complex, and hidden away.
Just by reading the message, we can gleen that it's related to debug information (the .debug_info and .debug_line sections of crt1.o's debug file is mentioned). Note the /usr/lib/debug/ path, which just contains debug information, the other crt1.o is a "stripped" file...
The format string is found in the binutils project, specifically bfd/elfcode.h. BFD being Binary File Descriptor - the GNU way to handle object files across a number of system architectures.
BFD is an intermediate format used for binary files - GCC will employ BFD before it finally writes an a.out, ELF, or other binary.
Looking into the manual, we can find some interesting snippets of knowledge:
[...] with each entry in the hash table the a.out linker keeps the index the symbol has in the final output file (this index number is used so that when doing a relocateable link the symbol index used in the output file can be quickly filled in when copying over a reloc).
[source]
The standard records contain only an address, a symbol index, and a type field. [source]
This means that these errors are issued due to relocations that are related to specific (missing?) 'symbols'. A 'symbol' in this context is any named 'thing' - e.g: functions and variables.
As these 'invalid symbols' appear to be resolved by simply declaring main(), I would guess that some (all?) of these symbol indexes are derived from main(), its debug information, and/or relations.
I can't tell you what is supposed to be at the symbol indexes mentioned (2, 11, 12, 13, 21), but it is interesting that my tests yielded the same list of symbol indexes.
Running ld with crt1.o alone gives us similar output:
$ ld /usr/lib/x86_64-linux-gnu/crt1.o
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 12
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21
ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x12): undefined reference to `__libc_csu_fini'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x19): undefined reference to `__libc_csu_init'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x25): undefined reference to `__libc_start_main'

gcc shared library failed linking to glibc

I'm writing a simple C shared library using Eclipse CDT under Linux 64bit.
The code has one reference to the rand() function in the <stdlib.h> It compiles fine but when linking it reports the following error from the linker:
gcc -shared -o "libalg.so" ./sort.o
/usr/bin/ld: ./sort.o: relocation R_X86_64_PC32 against undefined symbol `rand##GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
sort.o is the object file compiled from the file. libalg.so is the target shared library name.
Can anyone explaining why this happen?
Thanks.
On x86_64 architecture gcc requires you to use -fPIC i.e Position Independent Code by default.
The underlying reason for the error is that the relocation type for the symbol rand is of type R_X86_64_PC32 which means that it is PC relative and should lie within 32bit offset from the following instruction.
But the current architecture is of x86_64 type which means that it can lie anywhere within the 64bit address space.
So the dynamic linker actually can not link a symbol with such a relocation type.
Either you have to use -fPIC or compile your code using the -mcmodel=large which will actually make the relocation type to R_X86_64_64.
For more details on how linking is done refer to this great blog by Eli Bendersky

linker error: what could be going on?

I know not many people have telepathic powers here, but I will try to give as much info as I can so someone can help me debug what I think is a linker error in some program I'm trying to compile.
So, the program is cilkprof (see here, warning: tgz file). Within it is a Makefile for which I only changed the var CXX = icpc to CXX = g++. All else is equal.
/usr/bin/ld: ../../3rdparty/pintool/intel64/lib/libpin.a(util_host_ia32e.os):
relocation R_X86_64_PC32 against symbol `DoXsave' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [linux64/cilkprof.so] Error 1
I know I should be understanding that libpin.a should be recompiled with -fPIC, but the pin version I have is already compiled. Any idea what I may be doing wrong? Please ask if something is not clear. Thanks.
It seems to me that the Makefile is trying to build a shared library and link it to a static non-PIC library, which is AFAIK, something you can't do. So if you can not recompile the libray with -fPIC then the only solution I see is to modify the Makefile and build a static library instead.

Resources