Загрузка данных
import sys
import subprocess
import os
def main():
# CMake passes the real objcopy path as the very first argument to the script
if len(sys.argv) < 2:
print("[LMA Filter] Error: No real objcopy path provided.")
sys.exit(1)
# Index 1 is the absolute path to objcopy from Zephyr SDK
real_objcopy = sys.argv[1]
# Index 2 and onwards are the native flags passed by Zephyr
args = sys.argv[2:]
# Check if this call is the destructive LMA adjust step with the '*' wildcard
is_lma_adjust = any("--change-section-lma" in arg for arg in args) and any("*" in arg for arg in args)
if is_lma_adjust:
print("[LMA Filter] Intercepting destructive wildcard LMA adjust call...")
# 1. Extract the offset value (e.g., +3758096384)
offset = ""
for arg in args:
if arg.startswith("*+") or arg.startswith("*-"):
offset = arg[1:] # Strip the wildcard asterisk
break
# 2. Dynamically determine the path to readelf binary in the toolchain folder
sdk_bin_dir = os.path.dirname(real_objcopy)
readelf_bin = os.path.join(sdk_bin_dir, "arm-zephyr-eabi-readelf")
if not os.path.exists(readelf_bin):
for file in os.listdir(sdk_bin_dir):
if file.endswith("readelf"):
readelf_bin = os.path.join(sdk_bin_dir, file)
break
# 3. Read the section headers structure using -SW (Wide mode to prevent trimming name...)
res = subprocess.run([readelf_bin, "-SW", "zephyr.elf"], capture_output=True, text=True)
# 4. Parse section headers and filter only those starting with 0x8 (SDRAM/FLASH range)
lma_args = []
for line in res.stdout.splitlines():
parts = line.split()
# Skip empty lines, headers, or metadata lines
if len(parts) < 3 or "Адрес" in line or "Address" in line:
continue
# Remove brackets and symbols commonly added by readelf formatting
clean_parts = [p.replace('[', '').replace(']', '') for p in parts]
vma_addr = ""
sec_name = ""
# Scan elements to find the 8-digit VMA address starting with '8'
for i, part in enumerate(clean_parts):
if len(part) == 8 and part.startswith('8'):
vma_addr = part
# Section name usually precedes the VMA address
if i > 0:
sec_name = clean_parts[i-1]
if sec_name.isdigit() and i > 1: # Handle cases where index number is parsed
sec_name = clean_parts[i-2]
break
if not vma_addr:
continue
# Fallback check to prevent section types from being misidentified as names
if sec_name in ["PROGBITS", "NOBITS", "ARM_EXIDX", "SYMTAB", "STRTAB"]:
if clean_parts[1].isdigit():
sec_name = clean_parts[2]
else:
sec_name = clean_parts[1]
# Enforce the 0x8 rule and filter out uninitialized data sections (NOBITS)
if vma_addr.startswith('8') and sec_name:
if "bss" not in sec_name and "noinit" not in sec_name:
lma_args.extend(["--change-section-lma", f"{sec_name}{offset}"])
# 5. Clean up old destructive wildcard arguments passed by Zephyr
cleaned_args = []
skip_next = False
for arg in args:
if skip_next:
skip_next = False
continue
if arg == "--change-section-lma":
skip_next = True
continue
if arg.startswith("!.dtcm") or arg.startswith("!bss") or arg.startswith("!noinit"):
continue
cleaned_args.append(arg)
# 6. Execute real objcopy only with the specific targeted section list
if lma_args:
# Strip duplicate arguments if any occurred during parsing loops
unique_lma = []
for item in lma_args:
if item not in unique_lma:
unique_lma.append(item)
final_cmd = [real_objcopy] + unique_lma + cleaned_args
print(f"[LMA Filter] Found {len(unique_lma)//2} targeted sections in 0x8 range. Executing specific adjust...")
subprocess.run(final_cmd, check=True)
else:
print("[LMA Filter] Warning: No valid 0x8 sections found. Falling back to original command.")
subprocess.run([real_objcopy] + args, check=True)
else:
# Pass-through for all other standard objcopy steps (e.g. hex/bin conversions)
subprocess.run([real_objcopy] + args, check=True)
if __name__ == "__main__":
main()