cc_library_static {
    name: "liblinker_malloc",
    defaults: ["linux_bionic_supported"],
    recovery_available: true,

    srcs: [
        "linker_memory.cpp",
    ],
    cflags: [
        "-Wall",
        "-Werror",
    ],

    // We need to access Bionic private headers in the linker.
    include_dirs: ["bionic/libc"],

    static_libs: ["libasync_safe", "libbase"],
}

// This is used for bionic on (host) Linux to bootstrap our linker embedded into
// a binary.
//
// Host bionic binaries do not have a PT_INTERP section, instead this gets
// embedded as the entry point, and the linker is embedded as ELF sections in
// each binary. There's a linker script that sets all of that up (generated by
// extract_linker), and defines the extern symbols used in this file.
cc_object {
    name: "linker_wrapper",
    host_supported: true,
    device_supported: false,
    target: {
        linux_bionic: {
            enabled: true,
        },
        linux_glibc: {
            enabled: false,
        },
        darwin: {
            enabled: false,
        },
    },

    cflags: [
        "-fno-stack-protector",
        "-Wstrict-overflow=5",
        "-fvisibility=hidden",
        "-Wall",
        "-Wextra",
        "-Wno-unused",
        "-Werror",
    ],

    srcs: [
        "linker_wrapper.cpp",
    ],
    arch: {
        x86_64: {
            srcs: ["arch/x86_64/begin.S"],
        },
    },

    prefix_symbols: "__dlwrap_",

    // We need to access Bionic private headers in the linker.
    include_dirs: ["bionic/libc"],
}

filegroup {
    name: "linker_sources",
    srcs: [
        "dlfcn.cpp",
        "linker.cpp",
        "linker_block_allocator.cpp",
        "linker_dlwarning.cpp",
        "linker_cfi.cpp",
        "linker_config.cpp",
        "linker_gdb_support.cpp",
        "linker_globals.cpp",
        "linker_libc_support.c",
        "linker_libcxx_support.cpp",
        "linker_main.cpp",
        "linker_namespaces.cpp",
        "linker_logger.cpp",
        "linker_mapped_file_fragment.cpp",
        "linker_phdr.cpp",
        "linker_sdk_versions.cpp",
        "linker_soinfo.cpp",
        "linker_tls.cpp",
        "linker_utils.cpp",
        "rt.cpp",
    ],
}

filegroup {
    name: "linker_sources_arm",
    srcs: [
        "arch/arm/begin.S",
        "linker_exidx_static.c",
    ],
}

filegroup {
    name: "linker_sources_arm64",
    srcs: [
        "arch/arm64/begin.S",
        "arch/arm64/tlsdesc_resolver.S",
    ],
}

filegroup {
    name: "linker_sources_x86",
    srcs: [
        "arch/x86/begin.S",
    ],
}

filegroup {
    name: "linker_sources_x86_64",
    srcs: [
        "arch/x86_64/begin.S",
    ],
}

filegroup {
    name: "linker_sources_mips",
    srcs: [
        "arch/mips/begin.S",
        "linker_mips.cpp",
    ],
}

filegroup {
    name: "linker_sources_mips64",
    srcs: [
        "arch/mips64/begin.S",
        "linker_mips.cpp",
    ],
}

filegroup {
    name: "linker_version_script",
    srcs: ["linker.generic.map"],
}

filegroup {
    name: "linker_version_script_arm",
    srcs: ["linker.arm.map"],
}

cc_defaults {
    name: "linker_defaults",
    arch: {
        arm: {
            cflags: ["-D__work_around_b_24465209__"],
        },
        x86: {
            cflags: ["-D__work_around_b_24465209__"],
        },
    },

    // -shared is used to overwrite the -Bstatic and -static
    // flags triggered by LOCAL_FORCE_STATIC_EXECUTABLE.
    // This dynamic linker is actually a shared object linked with static libraries.
    ldflags: [
        "-shared",
        "-Wl,-Bsymbolic",
        "-Wl,--exclude-libs,ALL",
        "-Wl,-soname,ld-android.so",
    ],

    cflags: [
        "-fno-stack-protector",
        "-Wstrict-overflow=5",
        "-fvisibility=hidden",
        "-Wall",
        "-Wextra",
        "-Wunused",
        "-Werror",

        // Define _USING_LIBCXX so <stdatomic.h> defers to the <atomic> header. When a Soong module
        // uses the platform libc++, Soong automatically passes this macro, but the dynamic linker
        // links against libc++ manually.
        "-D_USING_LIBCXX",
    ],

    // TODO: split out the asflags.
    asflags: [
        "-fno-stack-protector",
        "-Wstrict-overflow=5",
        "-fvisibility=hidden",
        "-Wall",
        "-Wextra",
        "-Wunused",
        "-Werror",
    ],

    product_variables: {
        debuggable: {
            cppflags: ["-DUSE_LD_CONFIG_FILE"],
        },
    },

    cppflags: ["-Wold-style-cast"],

    // we are going to link libc++_static manually because
    // when stl is not set to "none" build system adds libdl
    // to the list of static libraries which needs to be
    // avoided in the case of building loader.
    stl: "none",

    // we don't want crtbegin.o (because we have begin.o), so unset it
    // just for this module
    nocrt: true,

    static_executable: true,

    // Leave the symbols in the shared library so that stack unwinders can produce
    // meaningful name resolution.
    strip: {
        keep_symbols: true,
    },

    // Insert an extra objcopy step to add prefix to symbols. This is needed to prevent gdb
    // looking up symbols in the linker by mistake.
    prefix_symbols: "__dl_",

    sanitize: {
        hwaddress: false,
    },
}

cc_binary {
    defaults: ["linux_bionic_supported", "linker_defaults"],
    srcs: [ ":linker_sources" ],

    arch: {
        arm: {
            srcs: [ ":linker_sources_arm" ],
            version_script: ":linker_version_script_arm",
        },
        arm64: {
            srcs: [":linker_sources_arm64"],
            version_script: ":linker_version_script",
        },
        x86: {
            srcs: [":linker_sources_x86"],
            version_script: ":linker_version_script",
        },
        x86_64: {
            srcs: [":linker_sources_x86_64"],
            version_script: ":linker_version_script",
        },
        mips: {
            srcs: [":linker_sources_mips"],
            version_script: ":linker_version_script",
        },
        mips64: {
            srcs: [":linker_sources_mips64"],
            version_script: ":linker_version_script",
        },
    },

    // We need to access Bionic private headers in the linker.
    include_dirs: ["bionic/libc"],

    static_libs: [
        "libc_nomalloc",
        "libm",
        "libziparchive",
        "libutils",
        "libbase",
        "libz",

        "libasync_safe",

        "liblog",
        "libc++_static",

        // Important: The liblinker_malloc should be the last library in the list
        // to overwrite any other malloc implementations by other static libraries.
        "liblinker_malloc",
    ],

    name: "linker",
    symlinks: ["linker_asan"],
    recovery_available: true,
    multilib: {
        lib32: {
            cflags: ["-DLIB_PATH=\"lib\""],
        },
        lib64: {
            cflags: ["-DLIB_PATH=\"lib64\""],
            suffix: "64",
        },
    },
    system_shared_libs: [],

    // Opt out of native_coverage when opting out of system_shared_libs
    native_coverage: false,

    target: {
        android: {
            static_libs: ["libdebuggerd_handler_fallback"],
        },
    },
    compile_multilib: "both",
    xom: false,
}

cc_library {
    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols ld-android.so pulls from
    // libgcc.a are made static to ld-android.so.  This in turn ensures that libraries that
    // a) pull symbols from libgcc.a and b) depend on ld-android.so will not rely on ld-android.so
    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
    // we use this property to make sure libc.so has its own copy of the code from
    // libgcc.a it uses.
    //
    // DO NOT REMOVE --exclude-libs!

    ldflags: [
        "-Wl,--exclude-libs=libgcc.a",
        "-Wl,--exclude-libs=libgcc_stripped.a",
        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
        "-Wl,--exclude-libs=libclang_rt.builtins-x86-android.a",
        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
    ],

    // for x86, exclude libgcc_eh.a for the same reasons as above
    arch: {
        arm: {
            version_script: "linker.arm.map",
        },
        arm64: {
            version_script: "linker.generic.map",
        },
        x86: {
            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
            version_script: "linker.generic.map",
        },
        x86_64: {
            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
            version_script: "linker.generic.map",
        },
        mips: {
            version_script: "linker.generic.map",
        },
        mips64: {
            version_script: "linker.generic.map",
        },
    },

    srcs: ["ld_android.cpp"],
    cflags: [
        "-Wall",
        "-Wextra",
        "-Wunused",
        "-Werror",
    ],
    stl: "none",

    name: "ld-android",
    defaults: ["linux_bionic_supported"],
    recovery_available: true,

    nocrt: true,
    system_shared_libs: [],

    // Opt out of native_coverage when opting out of system_shared_libs
    native_coverage: false,

    sanitize: {
        never: true,
    },
}

cc_test {
    name: "linker-unit-tests",

    cflags: [
        "-g",
        "-Wall",
        "-Wextra",
        "-Wunused",
        "-Werror",
    ],

    // We need to access Bionic private headers in the linker.
    include_dirs: ["bionic/libc"],

    srcs: [
        // Tests.
        "linker_block_allocator_test.cpp",
        "linker_config_test.cpp",
        "linked_list_test.cpp",
        "linker_sleb128_test.cpp",
        "linker_utils_test.cpp",

        // Parts of the linker that we're testing.
        "linker_block_allocator.cpp",
        "linker_config.cpp",
        "linker_test_globals.cpp",
        "linker_utils.cpp",
    ],

    static_libs: [
        "libasync_safe",
        "libbase",
        "liblog",
    ],
}