Command for retrieving for which architecture a library was built - shell

I remember that sometimes ago I was able to understand for which architecture a library (e.g. a .so or .a file) was built.
It was a shell command but now I cannot remember it.
Does somemone know it?
Thanks!

More possible options:
$ objdump -a /lib/libc.so.6
/lib/libc.so.6: file format elf64-x86-64
/lib/libc.so.6
$ objdump -f /lib/libc.so.6
/lib/libc.so.6: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x000000000001efc0

Maybe there is a better way, but generally the file command gives this information:
$ file /lib/libuuid.so.1.3.0
/lib/libuuid.so.1.3.0: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped
You may also try readelf:
readelf -h /lib/libuuid.so.1.3.0

Related

Linking 32- and 64-bit code together into a single binary

In a comment to this question,
Unexpected behaviour in simple pointer arithmetics in kernel space C code,
Michael Petch wrote, "The 64-bit ELF format supports 32-bit code sections."
I have a working program that includes both 32- and 64-bit code and switches between them. I have never been able to figure out how to link compiler-generated 32- and 64-bit code together without a linker error, so all the 32-bit code is written in assembly. As the project has become more complex, maintenance of the 32-bit assembly code has become more onerous.
Here is what I have:
test32.cc is compiled with -m32.
All the other source files are compiled without that flag and with -mcmodel=kernel.
In the linker script:
OUTPUT_FORMAT("elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
In the Makefile:
LD := ld
LDFLAGS := -Map $(TARGET).map -n --script $(LDSCRIPT)
$(LD) $(LDFLAGS) -b elf32-x86-64 $(OBJS64) -b elf32-i386 $(OBJS32) -o $#
I get the error:
ld: i386 architecture of input file 'test32.o' is incompatible with i386:x86-64 output
Changing OUTPUT_ARCH to i386 causes similar errors from all the 64-bit object modules.
I'm using:
gcc 5.4.1
GNU ld (GNU Binutils for Ubuntu) 2.26.1

How to generate symbol table with arm gcc

I would like to create a symbol definition table to be used in a separate application during linking. ARM's armlink linker has the following flag but I'm using arm-eabi:
--symdefs=filename
The GNU objcopy utility has an option --extract-symbol that may do what you want. It generates an object file with only symbol data - no actual code or data.
It is specifically intended to generate a .sym file for use in the VxWorks RTOS which has a command shell and dynamic linker/loader that uses this information. It is also used by the VxWorks host shell and source-level debugger.
The binutils nm utility on the other hand generates output very similar to armlink's --symdefs which you might easily post-process into exactly the form you need.
-Wl,-Map -Wl,mapfile -Wl,--cref
added to the final gcc (link) command line should do the trick.
This the correct answer from arm gnu launchpad:
Do you intend to load the symdef file with the GNU toolchain or with armcc one? If the former I think using nm on the object file and then linking with -R <filename> would work. So you would do arm-none-eabi-nm -D ./prog > ./prog.defsym after linking prog and then arm-none-eabi-gcc -Wl,-R,./prog.defsym when you want to use this.

Determine load address and entry point of stripped Linux Kernel image

I have a crosscompiling toolchain for an embedded system (mipsel) on my x86 Linux. I know how to build a custom kernel (let's call the image "vmlinux") for it and how to strip that image via
objcopy -S -O binary vmlinux vmlinux.bin
For further processing I also need the load address and entry point of the image. Before stripping it is no problem to determine them via scripts/mksysmap or, more explicitly, via
nm -n vmlinux | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > System.map
Then I can determine the load address and entry point via
awk '/A _text/ { print "0x"$1; }' < _System.map
awk '/T kernel_entry/ { print "0x"$1; }' < System.map
Now the challenge is that sometimes I do not build the kernel by myself, but get a pre-built kernel after it has already been stripped of its symbols via objcopy. Can anybody tell me how to do this? I am not very proficient in kernel building and toolchain usage. Both nm and objdump do not like the stripped image, saying
vmlinux.bin: File format not recognized
From the objcopy manual page
objcopy can be used to generate a raw binary file by using an output target of binary (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the virtual address of the lowest section copied into the output file.
Here is an example that could be used on the PowerPC architecture:
original vmlinux
bash-3.2$ file vmlinux
vmlinux: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, not stripped
stripped vmlinux is considered a "data" file
bash-3.2$ file vmlinux.bin
vmlinux.bin: data
convert binary to ELF format for the PowerPC
bash-3.2$ powerpc-440fp-linux-objcopy -I binary vmlinux.bin -B powerpc -O elf32-powerpc vmlinux.bin.x
output of vmlinux is now considered an ELF file
bash-3.2$ file vmlinux.bin.x
vmlinux.bin.x: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), not stripped
You must pass the -I, -B and -O parameter. You can get this parameters from your objcopy documentation.
But since your binary is stripped already trying to decompile it might not be worthwhile since the section information is not available. All of the data in the file will be dumped into the .data secion.

Can't link assembly file in Mac OS X using ld

I'm trying to run a basic assembly file using 64 Bit Mac OS X Lion, using nasm and ld which are installed by default with Xcode.
I've written an assembly file, which prints a character, and I got it to build using nasm.
nasm -f elf -o program.o main.asm
However, when I go to link it with ld, it fails with quite a few errors/warnings:
ld -o program program.o
ld: warning: -arch not specified
ld: warning: -macosx_version_min not specificed, assuming 10.7
ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)
ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib
ld: entry point (start) undefined. Usually in crt1.o for inferred architecture x86_64
So, I tried to rectify a few of these issues, and got nowhere.
Here's one of things I've tried:
ld -arch i386 -e _start -o program program.o
Which I thought would work, but I was wrong.
How do you make the object file a compatible architecture that nasm and ld will agree with?
Also, how would you define the entry point in the program (right now I'm using global _start in .section text, which is above _start, which doesn't seem to do much good.)
I'm a bit confused as to how you would successfully link an object file to a binary file using ld, and I think I'm just missing some code (or argument to nasm or ld) that will make them agree.
Any help appreciated.
You need to use global start and start:, no underscore. Also, you should not be using elf as the arch. Here is a bash script I use to assemble my x86-64 NASM programs on Mac OS X:
#!/bin/bash
if [[ -n "$1" && -f "$1" ]]; then
filename="$1"
base="${filename%%.*}"
ext="${filename##*.}"
nasm -f macho64 -Ox "$filename" \
&& ld -macosx_version_min 10.7 "${base}.o" -o "$base"
fi
If you have a file called foo.s, this script will first run
nasm -f macho64 -Ox foo.s
Which will create foo.o. The -Ox flag makes NASM do some extra optimization with jumps (i.e. making them short, near or far) so that you don't have to do it yourself. I'm using x86-64, so my code is 64-bit, but it looks like you're trying to assemble 32-bit. In that case, you would use -f macho32. See nasm -hf for a list of valid output formats.
Now, the object file will be linked:
ld -macosx_version_min 10.7 foo.o -o foo
I've set the -macosx_version_min option to quiet NASM down and prevent a warning. You don't have to set it to Lion (10.7). This will create an executable called foo. With any luck, typing ./foo and hitting return should run your program.
In regard to the ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib warning, I get that every time too and I'm not sure why, but everything seems fine when I run the executable.
OK, looking at your samples I assume you either used a generic nasm or linux assembly tutorial.
The first thing you need to take care of is the binary format created by nasm.
Your post states:
ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)
Thats the result of the '-f elf' parameter which tells nasm you want a 32bit ELF object (which would be the case for e.g. linux). But since you're on OSX what you want is a Mach-O object.
Try the following:
nasm -f macho64 -o program.o main.asm
gcc -o program program.o
Or if you wan't to create a 32bit binary:
nasm -f macho32 -o program.o main.asm
gcc -m32 -o program program.o
Regarding the _start symbol - if you wan't to create a simple program that will be able
to use the provided libc system functions then you shouldn't use _start at al.
It's the default entry point ld will look for and normaly it's provided in your libc / libsystem.
I suggest you try to replace the _start in your code by something like '_main'
and link it like the example above states.
A generic libc-based assembly template for nasm could look like this:
;---------------------------------------------------
.section text
;---------------------------------------------------
use32 ; use64 if you create 64bit code
global _main ; export the symbol so ld can find it
_main:
push ebp
mov ebp, esp ; create a basic stack frame
[your code here]
pop ebp ; restore original stack
mov eax, 0 ; store the return code for main in eax
ret ; exit the program
In addition to this I should mention that any call's you do on OSX need to use an aligned stack frame or your code will just crash.
There are some good tutorials on that out there too - try searching for OSX assembly guide.
It's probably easier just to let gcc do the heavy lifting for you, rather than trying to drive ld directly, e.g.
$ gcc -m32 program.o -o program
The mac gcc compiler won't link elf objects. You need a cross compiler...
http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux
Then you can proceed with something similar to this...
/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o

rpath=$ORIGIN not having desired effect?

I've got a binary "CeeloPartyServer" that needs to find libFoundation.so at runtime, on a FreeBSD machine. They're both in the same directory. I compile (on another platform, using a cross compiler) CeeloPartyServer using linker flag -rpath=$ORIGIN.
> readelf -d CeeloPartyServer |grep -i rpath
0x0000000f (RPATH) Library rpath: [$ORIGIN]
> ls
CeeloPartyServer Contents Foundation.framework libFoundation.so
> ./CeeloPartyServer
/libexec/ld-elf.so.1: Shared object "libFoundation.so" not found, required by "CeeloPartyServer"
Why isn't it finding the library when I try to run it?
My exact linker line is: -lm -lmysql -rpath=$ORIGIN.
I am pretty sure I don't have to escape $ or anything like that since my readelf analysis does in fact show that library rpath is set to $ORIGIN. What am I missing?
I'm assuming you are using gcc and binutils.
If you do
readelf -d CeeloPartyServer | grep ORIGIN
You should get back the RPATH line you found above, but you should also see some entries about flags. The following is from a library that I built.
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../lib]
0x000000000000001e (FLAGS) ORIGIN
0x000000006ffffffb (FLAGS_1) Flags: ORIGIN
If you aren't seeing some sort of FLAGS entries, you probably haven't told the linker to mark the object as requiring origin processing. With binutils ld, you do this by passing the -z origin flag.
I'm guessing you are using gcc to drive the link though, so in that case you will need to pass flag through the compiler by adding -Wl,-z,origin to your gcc link line.
Depending on how many layers this flag passes through before the linker sees it, you may need to use $$ORIGIN or even \$$ORIGIN. You will know that you have it right when readelf shows an RPATH header that looks like $ORIGIN/../lib or similar. The extra $ and the backslash are just to prevent the $ from being processed by other tools in the chain.
\$\ORIGIN if you are using chrpath and \$\$ORIGIN if you are providing directly in LDFLAGS
using ldd CeeloPartyServer to check the dependency .so is starting with ./ or not. (e.g. libFoundation.so and ./libFoundation.so)
For common situation it should be libFoundation.so and without the prefix ./
if ./ prefix is necessary for some uncommon case, make sure the CWD is the same folder with libFoundation.so, and the $ORIGIN would be invalid.
=======
For example:
g++ --shared -Wl,--rpath="\$ORIGIN" ./libFoundation.so -o lib2.so
would got a library lib2.so with ./libFoundation.so
g++ --shared -Wl,--rpath="\$ORIGIN" libFoundation.so -o lib2.so
would got libFoundation.so instead.

Resources