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


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()