AD6005: EnableOptimizeReferences¶
Summary¶
| Property | Value |
|---|---|
| ID | AD6005 |
| Name | EnableOptimizeReferences |
| Category | Performance |
| Severity | Warning |
| Applies to | PE (Windows) |
Description¶
This rule checks that PE binaries were linked with reference optimization (/OPT:REF) enabled. This linker option removes unreferenced functions and data (dead code elimination), reducing binary size and attack surface.
Why This Matters¶
Reference optimization removes unreferenced code and data, directly reducing attack surface. Dead code that's never called can still contain vulnerabilities and ROP gadgets that attackers can exploit.
Dead Code Security Risk¶
// Old debugging function, no longer called
void debug_dump_all() {
// Contains buffer overflow vulnerability
// Never called in production
// BUT: Still in binary without /OPT:REF
// Still provides ROP gadgets
}
// With /OPT:REF: Function removed entirely
// Without /OPT:REF: Vulnerability ships in production
Attack Surface Reduction¶
| Component | Without /OPT:REF | With /OPT:REF |
|---|---|---|
| Functions | All compiled | Only referenced |
| Data | All included | Only referenced |
| Gadgets | Maximum | Reduced |
| Binary size | Larger | Smaller |
What Gets Removed¶
Unreferenced functions:
- Old API compatibility shims
- Debug-only functions in release
- Unreachable error handlers
- Dead library code
Unreferenced data:
- Unused string tables
- Old configuration data
- Debug symbols
Size Impact¶
| Binary Type | Typical Reduction |
|---|---|
| Small apps | 5-15% |
| Libraries | 10-30% |
| Large apps | 5-20% |
| Static linked | 20-50% |
Security-Relevant Dead Code¶
Common sources of dead code with security implications:
1. Test/debug functions accidentally included
2. Old API versions kept for "compatibility"
3. Unreachable error paths with vulnerabilities
4. Library functions never actually called
5. Disabled features still compiled
Combined with ICF¶
Best results come from both optimizations:
link /OPT:REF /OPT:ICF myapp.obj
/OPT:REF → Removes unreferenced code
/OPT:ICF → Merges identical remaining code
Result: Minimal, optimized binary
- Smaller binaries: Unused code and data are removed
- Reduced attack surface: Less code means fewer potential vulnerabilities
- Security: Eliminates unreachable code that may contain security issues
- Release build indicator:
/OPT:REFshould be enabled for release builds
How to Fix¶
Enable reference optimization¶
# Link with REF enabled
link /OPT:REF myapp.obj
# Full release optimization (both REF and ICF)
link /OPT:REF /OPT:ICF myapp.obj
Disable incremental linking (required)¶
Reference optimization is incompatible with incremental linking:
Visual Studio¶
- Project Properties → Linker → Optimization
- Set "References" to "Yes (/OPT:REF)"
- Ensure "Link Incrementally" is set to "No (/INCREMENTAL:NO)"
CMake¶
Detection Method¶
aldur detects reference optimization availability by checking for the .textbss section. This section is created by incremental linking and indicates that /OPT:REF is disabled.
Example¶
Warning: Reference optimization not enabled
Binary appears to use incremental linking (.textbss section present).
Dead code elimination is disabled. Link with /INCREMENTAL:NO /OPT:REF for release builds.
Pass: Reference optimization available
What Gets Removed¶
With /OPT:REF enabled, the linker removes:
- Functions that are never called
- Global variables that are never referenced
- Static data that is unused
- COMDAT sections with no references
Preserving Specific Symbols¶
If you need to keep specific symbols that appear unused:
// Use pragma to prevent removal
#pragma comment(linker, "/INCLUDE:_my_required_symbol")
// Or use __declspec
__declspec(dllexport) void my_required_function() { }