Загрузка данных


import sys
import subprocess
import os
import re

def main():
    if len(sys.argv) < 2:
        print("[LMA Filter] Error: No real objcopy path provided.")
        sys.exit(1)

    real_objcopy = sys.argv[0] # Note: Fix possible sys.argv index shift based on your wrapper
    real_objcopy = sys.argv[1]
    args = sys.argv[2:]
    elf_path = "zephyr.elf"
    
    for arg in args:
        if arg.endswith("zephyr.elf"):
            elf_path = arg
            break

    # Skip if this is an internal ELF-to-ELF step
    is_elf_to_elf_adjust = any("--change-section-lma" in arg for arg in args) and ("zephyr.elf" in elf_path) and not any(fmt in " ".join(args) for fmt in ["ihex", "binary"])
    if is_elf_to_elf_adjust:
        sys.exit(0)

    is_hex_or_bin_generation = any("--output-target=" in arg for arg in args) or any(fmt in " ".join(args) for fmt in ["ihex", "binary"])

    if is_hex_or_bin_generation and os.path.exists(elf_path):
        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

        # Default fallback values if readelf fails
        code_end_vma = 0x80210000 
        
        # 1. Parse ELF first to find where the CODE region actually ends
        if os.path.exists(readelf_bin):
            res = subprocess.run([readelf_bin, "-SW", elf_path], capture_output=True, text=True)
            if res.returncode == 0:
                section_regex = re.compile(r'^\s*\[\s*\d+\]\s+([\.\w\-_]+)\s+(\w+)\s+([0-9a-fA-F]{8,16})\s+([0-9a-fA-F]{6,8})\s+([0-9a-fA-F]{6,8})')
                for line in res.stdout.splitlines():
                    match = section_regex.match(line)
                    if match:
                        sec_name, sec_type, vma_str, _, size_str = match.groups()
                        # .last_section or rodata usually marks the end of code/constants before the 0x80400000 gap
                        if sec_name in [".last_section", "rodata"] or (int(vma_str, 16) < 0x80400000 and sec_type != "NOBITS"):
                            vma_val = int(vma_str, 16)
                            size_val = int(size_str, 16)
                            end_pos = vma_val + size_val
                            if end_pos > code_end_vma:
                                code_end_vma = end_pos

        # Align the flash insertion point to a 4-byte boundary
        flash_data_start_lma = (code_end_vma - 0x20000000 + 3) & ~3
        print(f"[LMA Filter] Dynamic Pack: Code ends at LMA {hex(code_end_vma - 0x20000000)}. Data will start at LMA {hex(flash_data_start_lma)}")

        # 2. Build individual LMA shift arguments for each section
        dynamic_offsets = []
        if os.path.exists(readelf_bin):
            res = subprocess.run([readelf_bin, "-SW", elf_path], capture_output=True, text=True)
            if res.returncode == 0:
                section_regex = re.compile(r'^\s*\[\s*\d+\]\s+([\.\w\-_]+)\s+(\w+)\s+([0-9a-fA-F]{8,16})')
                current_flash_lma = flash_data_start_lma
                
                for line in res.stdout.splitlines():
                    match = section_regex.match(line)
                    if match:
                        sec_name, sec_type, vma_str = match.groups()
                        if sec_name in [".comment", ".symtab", ".strtab", ".shstrtab"] or sec_name.startswith(".debug"):
                            continue
                        
                        vma_val = int(vma_str, 16)
                        
                        if sec_type == "NOBITS":
                            continue
                        
                        # If the section belongs to the RAM/Data region (0x80400000+)
                        if vma_val >= 0x80400000:
                            # Calculate exactly how much we need to shift THIS specific section
                            # to place it sequentially in Flash
                            dynamic_offsets += ["--change-section-lma", f"{sec_name}={hex(current_flash_lma)}"]
                            
                            # Fetch size to increment pointer for the next section
                            size_res = re.search(r'^\s*\[\s*\d+\]\s+' + re.escape(sec_name) + r'\s+\w+\s+[0-9a-fA-F]+\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)', res.stdout, re.M)
                            if size_res:
                                current_flash_lma += (int(size_res.group(1), 16) + 3) & ~3
                        else:
                            # Standard code section (0x80000000) -> just shift down to 0x60000000
                            standard_lma = vma_val - 0x20000000
                            dynamic_offsets += ["--change-section-lma", f"{sec_name}={hex(standard_lma)}"]

        # Execute objcopy with custom tailored per-section LMA targets
        final_cmd = [real_objcopy] + dynamic_offsets + args
        subprocess.run(final_cmd, check=True)

        # 3. Print the final beautifully packed memory map
        if os.path.exists(readelf_bin):
            res = subprocess.run([readelf_bin, "-SW", elf_path], capture_output=True, text=True)
            if res.returncode == 0:
                print(f"\n[LMA Filter] === DYNAMICALLY PACKED MEMORY MAP FOR FLASH ===")
                print(f"{'Section Name':<28} | {'Original VMA':<12} | {'Resulting LMA (Flash)':<22}")
                print("-" * 72)
                section_regex = re.compile(r'^\s*\[\s*\d+\]\s+([\.\w\-_]+)\s+(\w+)\s+([0-9a-fA-F]{8,16})')
                current_flash_lma = flash_data_start_lma
                
                for line in res.stdout.splitlines():
                    match = section_regex.match(line)
                    if not match:
                        continue
                    sec_name, sec_type, vma_str = match.groups()
                    if sec_name in [".comment", ".symtab", ".strtab", ".shstrtab"] or sec_name.startswith(".debug"):
                        continue
                    vma_val = int(vma_str, 16)
                    vma_formatted = f"0x{vma_val:08X}"
                    
                    if sec_type == "NOBITS":
                        print(f"{sec_name:<28} | {vma_formatted:<12} | {'--------':<22} [RAM-only / Ignored]")
                        continue
                        
                    if vma_val >= 0x80400000:
                        lma_formatted = f"0x{current_flash_lma:08X}"
                        size_res = re.search(r'^\s*\[\s*\d+\]\s+' + re.escape(sec_name) + r'\s+\w+\s+[0-9a-fA-F]+\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)', res.stdout, re.M)
                        if size_res:
                            current_flash_lma += (int(size_res.group(1), 16) + 3) & ~3
                    else:
                        lma_formatted = f"0x{(vma_val - 0x20000000):08X}"
                        
                    print(f"{sec_name:<28} | {vma_formatted:<12} | {lma_formatted:<22} -> OK (Dynamic Flash)")
                print("=" * 72 + "\n")
    else:
        subprocess.run([real_objcopy] + args, check=True)

if __name__ == "__main__":
    main()