Why Is My MPLAB® XC32 BIN File Huge and How Do I Fix It?
When you build with MPLAB® XC32 for a PIC32C/SAM microcontroller with an Arm® core, the binary (BIN) file is enormous. When you build with the Arm GNU® Toolchain, it’s small. Why is it different?
The short answer: you’re probably using the MPLAB XC32 #pragma config feature. Those configuration bits live in special, high-address regions on many devices. A BIN file is a flat, addressless binary dump from the lowest used address to the highest used address in the final Executable and Linkable Format (ELF). Since the file format has no concept of an address, the space between two data chunks will be filled with zeroes. Therefore, if one chunk is far away from another in the address space, you will get gap fill bloat.
Summary
Large MPLAB XC32 BIN files typically come from #pragma config, placing tiny chunks at high addresses. A raw BIN must fill the gap with zeros. To resolve this, you have three options: 1) Remove the pragma, 2) switch to HEX/SREC, or 3) exclude config sections when producing the BIN. You get the same functional image without hauling a truckload of zeros.
What's Happening Under the Hood?
#pragma config emits linker sections for device configuration words.
- The linker script places those sections in the device’s config or user row region. That region sits at high addresses, separate from your application flash.
 - xc32-objcopy -O binary must output a single contiguous byte range. It starts at the lowest used address and runs through the highest. Any holes become zeros in the BIN.
 
Think of it like this: your ELF has bytes at 0x00000000 and again at 0x00F00000. A raw BIN has no addresses, so it must include everything in between. This results in a significantly larger file size.
0x00000000 [ your .text/.rodata/.dinit in app flash ]
..........
..........
0x00F00000 [ configuration bits live up here ] <- tiny chunk
Why Does the BIN From the Arm GNU Toolchain Look Smaller?
The most common reason is that the Arm GNU Toolchain build you compared against didn’t emit config or fuse content into the ELF at those high addresses.
How Do I Get a Small BIN Again for PIC32C MCUs?
Pick an option that fits your programming flow.
Option A: Remove the config pragma
If you want behavior closer to your Arm GNU build, delete the #pragma config blocks from the source code. Program fuses/config via your programmer settings or a separate fuse file. Your BIN will then cover only the app region.
Option B: Use HEX or S-record Instead of BIN
The Intel® HEX and Motorola® SREC file formats preserve addresses; no gap fill. Many tools prefer these file formats.
xc32-objcopy -O ihex app.elf app.hex
# or
xc32-objcopy -O srec app.elf app.srec
Option C: Strip the config Sections When Making a BIN
Keep #pragma config in ELF for Integrated Development Environment (IDE)/programmer awareness, but exclude those sections from the BIN.
Typical section patterns to remove:
- .config_*
 - .userrow*
 - .fuse* or .gpnvm* (names vary by device family)
 
Example:
--remove-section ".config_* " \
--remove-section ".devcfg* " \
--remove-section ".userrow* " \
--remove-section ".fuse* " \
-O binary app.elf app_no_config.bin
Adjust patterns to match your map. Verify with xc32-objdump -h app.elf.
Option D: Emit BIN Only From the Sections in Application Flash
If you prefer an allowed section list, you can explicitly specify which sections to copy into the BIN file. Note that this option can be risky and difficult to maintain.
--only-section ".text* " \
--only-section ".rodata* " \
--only-section ".init* " \
--only-section ".fini* " \
--only-section ".dinit* " \
-O binary app.elf app_code.bin
Here are a few important points to keep in mind:
- Section names can vary by device family, command-line options used, and toolchain versions. Confirm with xc32-objdump -h or your map file.
 - Some bootloaders require .bin. If yours does, use Option C or D to keep the file lean.
 - If you strip config sections from the BIN, be sure your programming step still sets config bits somewhere.
 
New Feature Introduced in MPLAB XC32 v5.00 for Arm® Core Devices
Beginning with MPLAB XC32 v5.00 for Arm core devices (i.e., SAM, PIC32C), the default behavior of xc32-objdump has been updated to more closely align with the standard Arm GNU Toolchain’s objdump utility. As a result, initialized data (typically named.data) sections in RAM are now included in the generated BIN file, enhancing compatibility with the Arm GNU Toolchain.
Depending on your loader’s requirements, you may or may not wish to include .data sections in your BIN file. If your loader is designed to initialize data in RAM, the new default behavior will be appropriate. Conversely, if your loader is intended to program flash memory only, you can disable the setting of the ALLOC flag for sections initialized by MPLAB XC32’s data-initialization template mechanism using an available option.
This functionality is managed via two xc32-ld linker options:
- --alloc-dinit-mapping (default) applies the ALLOC flag to all sections initialized by MPLAB XC32 data initialization, resulting in their inclusion in the BIN file by xc32-objcopy.
 - --no-alloc-dinit-mapping prevents the ALLOC flag from being set on these sections, so they are excluded from the BIN file by xc32-objcopy.
 
Please note that these are linker options that determine how the ALLOC flag is set within the ELF file.