How to compare binary files, hex files, and Intel hex firmware files with meld
Mirror mirror on the wall, which is the most amazing solution of them all?
It's this one: from @kenorb!--for sure! I upvoted it. Now, let me show you how amazing it looks and how easy it is to use with meld
:

Quick summary
Get the latest version of my hex2xxdhex
function in my eRCaGuy_dotfiles repo here: .bash_useful_functions. Copy and paste that function to the bottom of your ~/.bashrc
file. Then, re-source your ~/.bashrc
file with . ~/.bashrc
. Finally, use my hex2xxdhex
function like this:
# pass multiple `.hex` files to convert to `.bin`, `.xxd.hex`, and
# `.xxd_short.hex` files
hex2xxdhex path/to/myfile1.hex path/to/myfile2.hex
# then compare the two output ".xxd.hex" or ".xxd_short.hex" files with `meld`
meld path/to/myfile1.xxd_short.hex path/to/myfile2.xxd_short.hex
meld path/to/myfile1.xxd.hex path/to/myfile2.xxd.hex
In the above comparison of the two *.xxd*.hex
files, you'll see all of the hex chars, followed by the binary/ASCII chars in a column on the right-hand-side, allowing you to more easily identify hex file differences between the two files.
The .xxd_short.hex
files are simply the same as the .xxd.hex
files, except with all lines containing only zeros removed. This way, if your hex file places portions of your firmware at drastically different address locations, all of the padded zeros between the two address locations are removed.
If your initial .hex
file is 3.5 MB, your .bin
file might be 45 MB, your .xxd.hex
file might be 200 MB, and your .xxd_short.hex
file (with all rows of pure zeros) might be 5 MB. meld
can compare two 5 MB files just fine, but it struggles with 200 MB files. That's why I generate the .xxd_short.hex
version too.
Other options:
# Compare **two** binary files in meld
meld <(xxd file1.bin) <(xxd file2.bin)
# Compare **three** binary files in meld
meld <(xxd file1.bin) <(xxd file2.bin) <(xxd file3.bin)
# (note that for regular text files, just do this)
meld file1.txt file2.txt
# Compare ASCII hex files which were previously created with
# `xxd file1.bin file1.hex`
meld file1.hex file2.hex
# one-liner to compare Intel hex my_firmware1.hex and my_firmware2.hex
objcopy --input-target=ihex --output-target=binary my_firmware1.hex 1.bin \
&& objcopy --input-target=ihex --output-target=binary my_firmware2.hex 2.bin \
&& meld <(xxd 1.bin) <(xxd 2.bin)
# one-liner to compare Intel hex my_firmware1.hex and my_firmware2.hex
# **with the Microchip XC32 compiler toolchain!**
xc32-objcopy --input-target=ihex --output-target=binary my_firmware1.hex 1.bin \
&& xc32-objcopy --input-target=ihex --output-target=binary my_firmware2.hex 2.bin \
&& meld <(xxd 1.bin) <(xxd 2.bin)
# Compare two binary files using CLI tools only (no `meld` GUI) since you might
# be ssh'ed onto a remote machine
diff -u --color=always <(xxd file1.bin) <(xxd file2.bin) | less -RFX
# Another nice tool to use, which is CLI-based, but GUI-like (probably via the
# `ncurses` library, I'm guessing)
vbindiff file1.bin file2.bin
Details:
Compare binary files with meld
First, install it in Linux Ubuntu with sudo apt install meld
. Then, use it to compare binary files like this:
# Compare binary files in meld
meld <(xxd file1.bin) <(xxd file2.bin)
# (note that for regular text files, just do this)
meld file1.txt file2.txt
The first command above gives you this view, highlighting the exact differences, on a line-by-line and character-by-character level, between the left and right files. Notice the highlighted slivers in the right scroll bar too, which indicate where lines differ in the entire file:

Navigation in Meld:
- You can find the next change with Alt + Down and the previous change with Alt + Up.
- Or, you can hover your cursor over the center space exactly between the left and right sides, and scroll up and down with the mouse wheel to jump just between the changes.
- You can type into and edit the left or right side, and save afterwards.
- You can use Ctrl + F in the left or right side to find.
- Limitation: it will not search around line wraps. For that, try
vbindiff
instead.
Great tool! I am going to use this extensively now as I compare microcontroller .hex
firmware files to identify minor differences between some builds, such as changed IP addresses, embedded filenames, or timestamps.
The ingeniousness of the command above is how it uses xxd
first to convert a binary file to a hex + binary ASCII-text-side-bar view so that you can see human-readable text as well as the hex code.
Compare standard .hex
files with meld
Perhaps you have previously converted binary files to .hex
files, like this:
# convert binary files to ASCII hex files with a human-readable binary
# ASCII-text-side-bar on the right
xxd file1.bin file1.hex
xxd file2.bin file2.hex
In that case, just use meld
directly:
meld file1.hex file2.hex
Compare Intel .hex
microcontroller firmware files with meld
Intex .hex
files don't have the nice human-readable binary ASCII-text-side-bar on the right. So, first we must convert them to binary .bin
files, using objcopy
, as this answer shows, like this:
# Convert an Intel hex firmware file to binary
objcopy --input-target=ihex --output-target=binary my_firmware1.hex my_firmware1.bin
objcopy --input-target=ihex --output-target=binary my_firmware2.hex my_firmware2.bin
Do not forget the my_firmware1.bin
part at the end or else you'll get an unexpected behavior: my_firmware1.hex
will be converted to binary in-place! Oh no! There goes your hex file!
Now, compare the binary files in meld
, using xxd
to convert them back to ASCII hex with the pretty human-readable side-bar:
meld <(xxd my_firmware1.bin) <(xxd my_firmware2.bin)
Even better, do both steps above in one, like this "one-liner":
# one-liner to compare my_firmware1.hex and my_firmware2.hex
objcopy --input-target=ihex --output-target=binary my_firmware1.hex 1.bin \
&& objcopy --input-target=ihex --output-target=binary my_firmware2.hex 2.bin \
&& meld <(xxd 1.bin) <(xxd 2.bin)
Keep in mind though you need to use your compiler's version of the objcopy
executable to do the above operations. So, for the Microchip MPLAB X XC32 compiler toolchain, for instance, use xc32-objcopy
instead of objcopy
:
# one-liner to compare my_firmware1.hex and my_firmware2.hex
# **with the Microchip XC32 compiler toolchain!**
xc32-objcopy --input-target=ihex --output-target=binary my_firmware1.hex 1.bin \
&& xc32-objcopy --input-target=ihex --output-target=binary my_firmware2.hex 2.bin \
&& meld <(xxd 1.bin) <(xxd 2.bin)
Using only non-GUI CLI tools (meld
is a GUI)...
If you really need to use non-GUI tools, such as through an ssh session, here are some more options. Alternatively, you could just scp
the file back to your local machine over ssh, and then use meld
as described above.
Pure CLI tools for binary comparison:
Use diff
: refer back to @kenorb's answer above]. Here are some of my own spins on those commands which I think are more useful:
# For short output
diff -u --color=always <(xxd file1.bin) <(xxd file2.bin)
# If your output is really long, pipe to `less -RFX`, like `git` does
diff -u --color=always <(xxd file1.bin) <(xxd file2.bin) | less -RFX
Example run and output:
eRCaGuy_hello_world/c$ diff -u --color=always <(xxd file1.bin) <(xxd file2.bin)
--- /dev/fd/63 2023-06-21 23:16:51.649582608 -0700
+++ /dev/fd/62 2023-06-21 23:16:51.649582608 -0700
@@ -53,8 +53,8 @@
00000340: 0500 0000 474e 5500 0200 00c0 0400 0000 ....GNU.........
00000350: 0300 0000 0000 0000 0280 00c0 0400 0000 ................
00000360: 0100 0000 0000 0000 0400 0000 1400 0000 ................
-00000370: 0300 0000 474e 5500 5a84 e8c3 58b3 e81e ....GNU.Z...X...
-00000380: d731 5fd2 0c0a 1aaf be99 ec8b 0400 0000 .1_.............
+00000370: 0300 0000 474e 5500 23ea bebd 1106 9feb ....GNU.#.......
+00000380: 14a4 4f55 e90b d6b0 bf57 e851 0400 0000 ..OU.....W.Q....
00000390: 1000 0000 0100 0000 474e 5500 0000 0000 ........GNU.....
000003a0: 0300 0000 0200 0000 0000 0000 0000 0000 ................
000003b0: 0200 0000 0600 0000 0100 0000 0600 0000 ................
@@ -510,7 +510,7 @@
00001fd0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001fe0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
-00002000: 0100 0200 4865 6c6c 6f20 576f 726c 642e ....Hello World.
+00002000: 0100 0200 4865 4c6c 6f20 576f 526c 642e ....HeLlo WoRld.
00002010: 0a00 0000 011b 033b 3000 0000 0500 0000 .......;0.......
00002020: 0cf0 ffff 6400 0000 2cf0 ffff 8c00 0000 ....d...,.......
00002030: 3cf0 ffff a400 0000 4cf0 ffff bc00 0000 <.......L.......
Here's a screenshot so you can more easily see the colored changes:

Use vbindiff
:
I first learned about this tool here: How-To Geek: How to Compare Binary Files on Linux.
Here is how to install and use it:
# 1. Install it
sudo apt update
sudo apt install vbindiff
# 2. use it; note that we do NOT need `xxd` here
vbindiff file1.bin file2.bin
# You should study the manual/help pages too. It is very useful:
vbindiff -h
man vbindiff
Here's what it looks like on the 2nd change shown above. As you can see, it has highlighted the exact character differences in red. It's a pretty nice tool:

Navigation:
- See
man vbindiff
for details. It's a short and easy manual.
- Press Space or Enter to go to the next difference. I hit Space twice to go to the 2nd difference in the screenshot above.
- Press Q or Esc to quit.
- You can scroll with the mouse scroll wheel, arrow keys, PageUp/Down keys, etc.
- Press T to toggle on scrolling only the top window.
- Press B to toggle on scrolling only the bottom window.
- Press F to find.
The navigation is really pretty limited. I don't see a way to go back up and find a previous change. Just quit and start again.
How did I produce the binary files used in the examples above?
Easy:
file1.c from my eRCaGuy_hello_world repo here: hello_world_extra_basic.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("Hello World.\n\n");
return 0;
}
file2.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("HeLlo WoRld.\n\n");
return 0;
}
Now produce the executables, file1.bin
and file2.bin
, from those C files above:
gcc -Wall -Wextra -Werror -O3 -std=gnu17 file1.c -o file1.bin && ./file1.bin
gcc -Wall -Wextra -Werror -O3 -std=gnu17 file2.c -o file2.bin && ./file2.bin
Then, of course, compare them!:
meld <(xxd file1.bin) <(xxd file2.bin)
See also
- My really-useful
hex2bin
and hex2xxdhex
Bash functions to aid your binary comparisons above, in my answer here: Stack Overflow: Bash function to mass-convert Intel *.hex
firmware files to *.bin
firmware files, and to *.xxd.hex
files for comparison in meld
- My answer on how to make
meld
your git difftool
in Windows, Mac, and Linux
cmp
has an-x
flag ("heXadecimal") which produces output formatted exactly as specified in the question, in conjunction with-l
:cmp -xl file1.bin file2.bin
. source