Similarly to How do I disassemble raw x86 code?, but then for the MIPS architecture: how do I disassemble raw MIPS code with objdump? I want to check the instructions in a vmlinux image, but to do so I now have to:
: > x.c
mipsel-linux-gnu-gcc -c -o x.o x.c
mipsel-linux-gnu-objcopy --add-section raw=vmlinux x.o
mipsel-linux-gnu-objcopy --remove-section .comment x.o
mipsel-linux-gnu-objdump -D x.o | less
Is there an easier way to do it? I've tried the below to no avail:
mipsel-linux-gnu-objdump -b elf32-tradlittlemips -mmips -Mgpr-names=O32,cp0-names=mips1,cp0-names=mips1,hwr-names=mips1,reg-names=mips1 -D vmlinux | less
It just spits out:
mipsel-linux-gnu-objdump: vmlinux: File format not recognized
If it helps, here is the output of some commands:
$ file x.o
x.o: ELF 32-bit LSB relocatable, MIPS, MIPS-I version 1 (SYSV), with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, not stripped
$ mipsel-linux-gnu-objdump -p x.o
x.o: file format elf32-tradlittlemips
private flags = 1006: [abi=O32] [mips1] [not 32bitmode] [PIC] [CPIC]
The target is an AR7 CPU.
Hmm, it seems easier than that. -b elf32-tradlittlemips does not work because the file is not an ELF executable, but binary. So, the correct option to be used is -b binary. The other option, -mmips makes objdump recognize the file as binary for MIPS. Since the target machine is little endian, I also had to add -EL to make the output match the output for x.o.
-mmips only includes the basic instruction set. The AR7 has a MIPS32 processor which has more instructions than just mips. To decode these newer MIPS32 instructions, use -mmips:isa32. A list of available ISAs can be listed with objdump -i -m.
The final command becomes:
mipsel-linux-gnu-objdump -b binary -mmips:isa32 -EL -D vmlinux
This would show registers like $3 instead of their names. To adjust that, I used the next additional options which are mentioned in mipsel-linux-gnu-objdump --help:
-Mgpr-names=32,cp0-names=mips32,cp0-names=mips32,hwr-names=mips32,reg-names=mips32
I chose for mips32 after reading:
http://www.linux-mips.org/wiki/AR7
http://www.linux-mips.org/wiki/Instruction_Set_Architecture
??? What's wrong with just:
mipsel-linux-gnu-gcc -c -o x.o x.c
mipsel-linux-gnu-objdump -D x.o
Is the problem that -D diassembles all the sections, code or not? Use -d then. Or -S to show assembly interleaved with source (implies -d).
or how about getting the assembly code from gcc:
mipsel-linux-gnu-gcc -S x.c
Use ODA, the online disassembler:
http://www.onlinedisassembler.com
Related
I have been working on a 32-bit operating system project written in C using GNU LD version 2.34 as the linker.
As part of the build process, I use the following command:
ld -m elf_i386 -nostdlib -T ld/loader.ld build/bootloader/loader.o build/bootloader/loader.elf -o loader_full.elf
When using GNU LD version 2.34, this command succeeds. However, when I use a version higher than this, I get the following error:
ld: cannot use executable file 'build/bootloader/loader.elf' as input to a link
If necessary, here is the full Makefile script:
CC_FLAGS = -g -m32 -ffreestanding -nostartfiles -nostdlib -fno-stack-protector
LD_FLAGS = -m elf_i386 -nostdlib
CC := gcc ${CC_FLAGS}
LD := ld ${LD_FLAGS}
BOOTLOADER_DRIVERS = kernel/drivers/disk/ata.c kernel/drivers/io/screen.c kernel/drivers/utils/mem.c kernel/drivers/utils/ports.c
raw: prep os-image.bin
convert_vmdk: os-image.vmdk
all: prep os-image.bin
ESFS_raw_write: ESFS_raw_write.c
gcc $^ -o $#
# run OS in QEMU
run:
qemu-system-i386 -drive format=raw,file=os-image.bin
# assemble boot sector
build/bootloader/boot_sect.bin: boot/boot_sect.asm
nasm $^ -f bin -o $#
# compile second stage bootloader
build/bootloader/loader_2.o build/drivers/*.o: boot/*.c ${BOOTLOADER_DRIVERS}
${CC} -c $^
mv loader.o build/bootloader/loader_2.o
mv *.o build/drivers/
# link object files into kernel loader
build/bootloader/loader.elf: build/bootloader/loader_2.o build/drivers/*.o
${LD} -T ld/loader.ld $^ -o $#
rm build/bootloader/loader_2.o
# assemble first stage bootloader
build/bootloader/loader.o: boot/loader.asm
nasm $^ -f elf -o $#
# link first and second stage bootloaders
build/bootloader/loader_full.elf: build/bootloader/loader.o build/bootloader/loader.elf
${LD} -T ld/loader.ld $^ -o $#
# make bootloader binary file
build/bootloader/loader.bin: build/bootloader/loader_full.elf
objcopy $^ -O binary $#
./scripts/pad_loader.sh
# clean up unnecessary files
# rm build/bootloader/*.o build/bootloader/*.elf build/drivers/*.o
build/kernel/interrupt.o: kernel/cpu/interrupt.asm
nasm $^ -f elf -o $#
# compile kernel & write to 10MB raw drive image
build/kernel/hdd.bin: kernel/drivers/*/*.c kernel/cpu/*.c kernel/libc/*.c build/kernel/interrupt.o kernel/*.c
${CC} $^ -o build/kernel/kernel.o -T ld/kernel.ld
./scripts/write_kernel_to_drive.sh
# concat 3 boot stages into os-image file
os-image.bin: build/bootloader/boot_sect.bin build/bootloader/loader.bin build/kernel/hdd.bin
cat $^ > $#
os-image.vmdk:
VBoxManage convertfromraw os-image.bin os-image.vmdk --format VMDK
VBoxManage internalcommands sethduuid /home/tim/Dev/OSDev/os-image.vmdk 6372c00a-a62e-4241-9a21-90fa4c22f019
# prepare directory structure for build process
prep:
mkdir -p build/bootloader
mkdir -p build/drivers
mkdir -p build/kernel
# clean up build files and os-image binary
clean:
-rm -rf build/
-rm *.bin *.vmdk
-rm ESFS_raw_write
The project is also on GitHub, so you can build it for yourself:
http://github.com/TimCve/OSDev.git
I have just come up with a similar problem.
It seems ld version GNU ld (GNU Binutils) 2.36.1 links the file into an executable format.
To fix it, add -r in your ld command to output a relocatable format file.
From the ld manual:
-r
--relocateable
Generate relocatable output--i.e., generate an output file that can in turn serve as input to ld. This is often called partial linking. As a side effect, in environments that support standard Unix magic numbers, this option also sets the output file's magic number to OMAGIC. If this option is not specified, an absolute file is produced. When linking C++ programs, this option will not resolve references to constructors; to do that, use -Ur. This option does the same thing as -i.
It's not that ld can't take ELF files as input. It's that it won't take executable files as input. The error is:
ld: cannot use executable file '...' as input to a link
See https://sourceware.org/bugzilla/show_bug.cgi?id=26223
Does it work to simply use chmod -x $# after building the .elf file?
In my (eclipse-based) multicore MCUXpresso project, I had to add this line to my post-build steps to modify a byte inside of the generated "*.o" file so the linker step which used that file wouldn't complain anymore. This happened after I updated to version 11.6 which includes the LD version mentioned previously. I originally found this on the forums for NXP MCUXpresso, but I assume it will work similarly for just about anyone:
dd if=/dev/zero of="${BuildArtifactFileName}.o" bs=1 seek=16 conv=notrunc count=2
NXP MCUXpresso fix
I'm new in assembly language, so i am following Dr.Paul Carter's pcasm tutorial(
http://pacman128.github.io/pcasm/
).
Exactly pdf file(http://pacman128.github.io/static/pcasm-book.pdf) page-33, and book's page-23
From that site, i downloaded Linux Example (http://pacman128.github.io/static/linux-ex.zip)
and at the terminal i input
nasm -f coff first.asm
gcc -c driver.c
nasm -f coff asm_io.o
gcc -o first driver.o first.o asm_io.o
But it returned it
Where is problem?
(Screenshot's command -lc is no matter, if there is no -lc, it returned the same thing)
For Linux asm_io doesn't work with 64-bit. You have to create 32-bit programs. Compile C files as 32-bit using the -m32 option. You also have to assemble asm_io.asm with a special define -d ELF_TYPE for this to work on Linux. Don't use coff. Commands like this should work:
nasm -f elf -d ELF_TYPE asm_io.asm
nasm -f elf first.asm
gcc -m32 -c driver.c
gcc -m32 -o first driver.o first.o asm_io.o
If you are truly on 32-bit Linux you will be able to omit -m32
I found that error is from asm_io.asm. You should have to modify asm_io.asm or check define lines.
I want to find inside a Makefile, whether I'm running on a 32-bit or 64-bit machine.
Is there any macro or environment variables that can be simply accessed from within Makefile?
I found this related answer on-line:
LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
# do 64 bit stuff here, like set some CFLAGS
else
# do 32 bit stuff here
endif
However, I doubt in all system getconf tool would be available or not.
tl;dr;
If all you need is to get the number of bits in long type in C in a portable way, it's ok to use getconf LONG_BIT.
Otherwise:
to detect host architecture, use config.guess shell script
to detect target architecture, use gcc -dumpmachine or gcc --help=target
Detecting host architecture
1) getconf
As mentioned by #Dummy00001, getconf is part of POSIX and is widely available, but it doesn't provide enough information.
Note that getconf LONG_BIT is just the number of bits in long type in C. E.g., it may be 32 on 16-bit or 64-bit machines. It's quite useless for determining host architecture.
2) uname
uname is part of POSIX as well, and it doesn't provide enough information too.
For example, it doesn't distinguish between hardfloat and softfloat ARM on Linux. Also, its architecture naming is not really portable.
3) /proc
You can use /proc to gather architecture info, e.g. /proc/cpuinfo on Linux. However, it's not portable and hard to parse.
4) config.guess
Finally, I recommend GNU config.guess script (source code). It is a standalone script that you can copy to your project. It is written in portable shell and should work on any UNIX.
$ sh config.guess
x86_64-pc-linux-gnu
This script is used in autotools, but you can use it without autotools too.
Detecting default target architecture of your toolchain
It usually makes sense to detect target architecture of toolchain being used. It's different from host architecture when cross-compiling.
1) gcc -E
You can parse gcc -E output to get toolchain tuple for target architecture of gcc:
$ gcc -v -E - </dev/null |& grep Target:
Target: x86_64-linux-gnu
This should work on any UNIX if you use GCC or clang.
Notes:
It prints the value of --target option passed to configure script when GCC was built. It's not affected by current compilations flags passed to GCC, like -m32 or -march.
Unlike config.guess, this toolchain tuple is distro-specific. E.g., different schemes are used in prebuilt toolchains in Debian and Gentoo.
2) gcc -dumpmachine
It seems that gcc -dumpmachine prints the same value as previous recipe:
$ gcc -dumpmachine
x86_64-linux-gnu
It works with GCC and clang.
3) gcc -print-multiarch
Another way to get toolchain tuple:
$ gcc -print-multiarch
x86_64-linux-gnu
It works with GCC, but not clang. Also, this option is known not to work in various cases:
on Debian, it's empty if multilib is disabled
on Gentoo, it's always empty
as mentioned by #Dummy00001, it may be empty for cross-compilation toolchains (I guess it depends on how toolchain was built)
Detecting target architecture depending on current flags
Some GCC options like -m32 or -march can affect target architecture.
1) gcc --help=target
This will print value of -march option deduced from default target architecture (configured when GCC was built) and current compilation options.
$ gcc -Q --help=target |& grep -e -march | awk '{print $2}'
x86-64
$ gcc -m32 -Q --help=target |& grep -e -march | awk '{print $2}'
i686
$ gcc -march=i386 -Q --help=target |& grep -e -march | awk '{print $2}'
i386
It doesn't work with clang.
The getconf is a POSIX tool, it should be available on all unix-like systems. But uname -m would be more portable and more traditional way to find the type of the system.
Otherwise, with high probability, you are looking in the wrong direction: the bit-ness of the host system doesn't necessarily match the bit-ness of the tool-chain. Tool-chain (compiler, linker) define what bit-ness the result would be. And the tool-chain could be customized by the user to accommodate for the local needs (e.g. compiling as 32-bit on a 64-bit OS), or even cross-compilation.
To find the bit-ness of the GCC (or clang) in your tool-chain, you can use that:
LBITS := $(shell $(CC) $(CFLAGS) -dM -E - </dev/null | grep -q "__LP64__" && echo 64 || echo 32)
Effectively, it queries what bit-ness the application is going to be compiled with, without doing actual compilation, but peeking at the compiler defines for the LP parameter, which denotes the "data model" of the architecture (LP64 means "long and pointer are 64-bit" (and, by omission, int is 32 bit); ILP32 means "int, long and pointer are 32-bit").
As long as you stay on the Linux, that would work. (You need to use the CFLAGS in the compiler invocation, since CFLAGS overridden by the user could use the -m32 or -m64 options to change the bit-ness of the output code.)
I am following a tutorial online made a while back and it says to use
ld -s -o testing test.o
to create an output file.
I'm getting the error of
ld: i386 architecture of input file 'test.o' is incompatible with i386:x86-64 output
when trying to run that line.
Test.o was created by nasm -f elf test.asm. It can't be created in 64-bit format sadly.
How should I go about combating this? Thanks so much for your time!!
You can't make a 64bit executable with 32bit code.
If you want to make a 32bit executable, you can use -m elf_i386:
$ ld -s -o test test.o
ld: i386 architecture of input file `test.o' is incompatible
with i386:x86-64 output
$ ld -s -o test test.o -m elf_i386
$
I am confused by this command. The man page http://linux.die.net/man/1/ld says it "emulates the emulation linker. You can list the available emulations with the --verbose or -V options." But what does the "available emulations" mean?
For example, I use the following command to link objects:
ld -r -nostdlib -L/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib \
-m elf_x86_64 --verbose ./arch/x86/x86_64.o ./mini-os_app.o ./blkfront.o ./events.o ./fbfront.o \
./gntmap.o ./gnttab.o ./hypervisor.o ./kernel.o ./lock.o ./main.o ./mm.o ./netfront.o ./sched.o \
./lib/ctype.o ./lib/math.o ./lib/printf.o ./lib/stack_chk_fail.o ./lib/string.o ./lib/sys.o \
./lib/xmalloc.o ./lib/xs.o ./xenbus/xenbus.o ./console/console.o ./console/xencons_ring.o \
./console/xenbus.o ./lwip.a -L./arch/x86 -lx86_64 -lc -lglib-2.0 -lvmi -o ./mini-os.o
GNU ld (GNU Binutils for Ubuntu) 2.22
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
i386linux
elf_l1om
elf_k1om
using internal linker script:
==================================================
(>>> scripts displayed here, neglected <<<)
==================================================
...
attempt to open /media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a succeeded
(>>> lots of *.o listed here for libc.a <<<)
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a)mm.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a)sched.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a)setup.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a)time.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/mini-os-x86_64-vmi/arch/x86/libx86_64.a)traps.o
...
attempt to open /media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libglib-2.0.a succeeded
(>>> why no *.o files listed here? <<<)
attempt to open /media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a succeeded
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-accessors.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-convenience.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-core.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-events.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-memory.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-read.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-interface.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-kvm.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-memory_cache.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-xen.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)lt1-libvmi_la-core.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)lt2-libvmi_la-memory.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-symbols.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)lt3-libvmi_la-core.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-kpcr.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)lt4-libvmi_la-memory.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-peparse.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-process.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)grammar.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)lexicon.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-cache.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-strmatch.o
(/media/wind/lab/xen/xen/xen-4.4.0/stubdom/cross-root-x86_64/x86_64-xen-elf/lib/libvmi.a)libvmi_la-file.o
As showed in the above outputs, it seems that each *.a library should have their own *.o listed. But what is the meaning if no *.o listed for a certain *.a library,such as glib-2.0.a showed above ?
Thank you in advance!
The ld -m option is used while linking .o files to create an executable file for a hardware platform provided as an argument with -m option.
E.g. if you specify ld -m elf_x86_64 ..., an executable file is created (assuming no error occurred) that can run on a x86_64 system. This is generally used during cross compiling. i.e. in the situation when you are trying to create an executable for a platform different from the one it is being built.