## 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](https://superuser.com/a/968863/425838)!--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][1]][1]


## Quick summary

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

```bash
# 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][2]][2]

Navigation in Meld:
1. You can find the next change with <kbd>Alt</kbd> + <kbd>Down</kbd> and the previous change with <kbd>Alt</kbd> + <kbd>Up</kbd>.
    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. 
1. You can type into and edit the left or right side, and save afterwards. 
1. You can use <kbd>Ctrl</kbd> + <kbd>F</kbd> 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:
```bash
# 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:
```bash
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](https://stackoverflow.com/a/37226481/4561887), like this:

```bash
# 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:
```bash
meld <(xxd my_firmware1.bin) <(xxd my_firmware2.bin)
```

Even better, do both steps above in one, like this "one-liner":
```bash
# 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](https://www.microchip.com/en-us/tools-resources/develop/mplab-xc-compilers), for instance, use `xc32-objcopy` instead of `objcopy`:

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

1. **Use `diff`:** refer back to [@kenorb's answer above](https://superuser.com/a/968863/425838)]. Here are some of my own spins on those commands which I think are more useful:
    ```bash
    # 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:

    ```diff
    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][3]][3]

1. **Use `vbindiff`:**
    I first learned about this tool here: [How-To Geek: How to Compare Binary Files on Linux](https://www.howtogeek.com/817201/compare-binary-files-linux/).

    Here is how to install and use it:
    ```bash
    # 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][4]][4]

    Navigation:
    1. See `man vbindiff` for details. It's a short and easy manual. 
    1. Press <kbd>Space</kbd> or <kbd>Enter</kbd> to go to the next difference. I hit <kbd>Space</kbd> twice to go to the 2nd difference in the screenshot above. 
    1. Press <kbd>Q</kbd> or <kbd>Esc</kbd> to quit. 
    1. You can scroll with the mouse scroll wheel, arrow keys, <kbd>PageUp/Down</kbd> keys, etc.
    1. Press <kbd>T</kbd> to toggle on scrolling only the _top_ window. 
    1. Press <kbd>B</kbd> to toggle on scrolling only the _bottom_ window. 
    1. Press <kbd>F</kbd> 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](https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world) repo here: [hello_world_extra_basic.c](https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/hello_world_extra_basic.c):
```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:**
```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:
```bash
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!:
```bash
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](https://stackoverflow.com/a/48979939/4561887)



  [1]: https://i.sstatic.net/Mzf5E.png
  [2]: https://i.sstatic.net/EoOau.jpg
  [3]: https://i.sstatic.net/wPr3J.png
  [4]: https://i.sstatic.net/xYT7l.jpg