Skip to main content
2 of 6
added 47 characters in body
Gabriel Staples
  • 2.1k
  • 2
  • 27
  • 39

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:

enter image description here

Quick summary

# 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:

enter image description here

Navigation in Meld:

  1. You can find the next change with Alt + Down and the previous change with Alt + Up.
    1. 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.
  2. You can type into and edit the left or right side, and save afterwards.
  3. You can use Ctrl + F in the left or right side to find.
    1. 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:

  1. 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:

    enter image description here

  2. Use vbindiff:

    # 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:

    enter image description here

    Navigation:

    1. See man vbindiff for details. It's a short and easy manual.
    2. Press Space or Enter to go to the next difference. I hit Space twice to go to the 2nd difference in the screenshot above.
    3. Press Q or Esc to quit.
    4. You can scroll with the mouse scroll wheel, arrow keys, PageUp/Down keys, etc.
    5. Press T to toggle on scrolling only the top window.
    6. Press B to toggle on scrolling only the bottom window.
    7. 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

  1. My answer on how to make meld your git difftool in Windows, Mac, and Linux
Gabriel Staples
  • 2.1k
  • 2
  • 27
  • 39