// ========================================================
// linker_wrapper - Linux Bionic (on the host)
// ========================================================

// 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.
package {
    default_applicable_licenses: ["bionic_linker_license"],
}

license {
    name: "bionic_linker_license",
    visibility: [":__subpackages__"],
    license_kinds: [
        "SPDX-license-identifier-BSD",
    ],
    license_text: [
        "NOTICE",
    ],
}

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: {
        arm64: {
            srcs: ["arch/arm64/begin.S"],
        },
        x86_64: {
            srcs: ["arch/x86_64/begin.S"],
        },
    },

    prefix_symbols: "__dlwrap_",

    header_libs: ["libc_headers"],

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

    // b/182338959
    bazel_module: { bp2build_available: false },
}

// ========================================================
// linker default configuration
// ========================================================

// Configuration for the linker binary and any of its static libraries.
cc_defaults {
    name: "linker_defaults",
    arch: {
        arm: {
            cflags: ["-D__work_around_b_24465209__"],
        },
        x86: {
            cflags: ["-D__work_around_b_24465209__"],
        },
    },

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

    // 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"],

    static_libs: [
        "libziparchive",
        "libbase",
        "libz",

        "libasync_safe",

        "liblog",
    ],

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

// ========================================================
// linker components
// ========================================================

// Enable a module on all targets the linker runs on (ordinary Android targets, Linux Bionic, and
// native bridge implementations).
cc_defaults {
    name: "linker_all_targets",
    defaults: ["linux_bionic_supported"],
    recovery_available: true,
    vendor_ramdisk_available: true,
    native_bridge_supported: true,
}

cc_library_static {
    name: "liblinker_main",
    defaults: ["linker_defaults", "linker_all_targets"],
    srcs: ["linker_main.cpp"],

    // Ensure that the compiler won't insert string function calls before ifuncs are resolved.
    cflags: ["-ffreestanding"],
}

cc_library_static {
    name: "liblinker_malloc",
    defaults: ["linker_defaults", "linker_all_targets"],
    srcs: ["linker_memory.cpp"],
}

cc_library_static {
    name: "liblinker_debuggerd_stub",
    defaults: ["linker_defaults", "linker_all_targets"],
    srcs: ["linker_debuggerd_stub.cpp"],
}

// ========================================================
// template for the linker binary
// ========================================================

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

filegroup {
    name: "linker_sources_arm",
    srcs: [
        "arch/arm/begin.S",
        "arch/arm_neon/linker_gnu_hash_neon.cpp",
    ],
}

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

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

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

cc_defaults {
    name: "linker_version_script_overlay",
    arch: {
        arm:    { version_script: "linker.arm.map"      },
        arm64:  { version_script: "linker.generic.map"  },
        x86:    { version_script: "linker.generic.map"  },
        x86_64: { version_script: "linker.generic.map"  },
    },
}

// A template for the linker binary. May be inherited by native bridge implementations.
cc_defaults {
    name: "linker_bin_template",
    defaults: ["linker_defaults"],

    srcs: [":linker_sources"],

    arch: {
        arm: {
            srcs: [":linker_sources_arm"],
        },
        arm64: {
            srcs: [":linker_sources_arm64"],
        },
        x86: {
            srcs: [":linker_sources_x86"],
        },
        x86_64: {
            srcs: [":linker_sources_x86_64"],
        },
    },

    // -shared is used to overwrite the -Bstatic and -static flags triggered by enabling
    // 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",
    ],

    // 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,
    },

    static_libs: [
        "liblinker_main",
        "liblinker_malloc",

        "libc++_static",
        "libc_nomalloc",
        "libc_dynamic_dispatch",
        "libm",
        "libunwind",
    ],

    // Ensure that if the linker needs __gnu_Unwind_Find_exidx, then the linker will have a
    // definition of the symbol. The linker links against libgcc.a, whose arm32 unwinder has a weak
    // reference to __gnu_Unwind_Find_exidx, which isn't sufficient to pull in the strong definition
    // of __gnu_Unwind_Find_exidx from libc. An unresolved weak reference would create a
    // non-relative dynamic relocation in the linker binary, which complicates linker startup.
    //
    // This line should be unnecessary because the linker's dependency on libunwind_llvm.a should
    // override libgcc.a, but this line provides a simpler guarantee. It can be removed once the
    // linker stops linking against libgcc.a's arm32 unwinder.
    whole_static_libs: ["libc_unwind_static"],

    system_shared_libs: [],

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

// ========================================================
// linker[_asan][64] binary
// ========================================================

cc_binary {
    name: "linker",
    defaults: [
        "linker_bin_template",
        "linux_bionic_supported",
        "linker_version_script_overlay",
    ],

    srcs: [
        "linker_translate_path.cpp",
    ],

    symlinks: ["linker_asan"],
    multilib: {
        lib64: {
            suffix: "64",
        },
    },

    compile_multilib: "both",

    recovery_available: true,
    vendor_ramdisk_available: true,
    apex_available: [
        "//apex_available:platform",
        "com.android.runtime",
    ],

    target: {
        android: {
            srcs: [
                "linker_debuggerd_android.cpp",
            ],
            static_libs: [
                "libc++demangle",
                "libdebuggerd_handler_fallback",
            ],
        },
        linux_bionic: {
            static_libs: [
                "liblinker_debuggerd_stub",
            ],
        },
        android_arm64: {
            pgo: {
                profile_file: "bionic/linker_arm_arm64.profdata",
            },
        },
        android_arm: {
            pgo: {
                profile_file: "bionic/linker_arm_arm64.profdata",
            },
        },
        android_x86_64: {
            pgo: {
                profile_file: "bionic/linker_x86_x86_64.profdata",
            },
        },
        android_x86: {
            pgo: {
                profile_file: "bionic/linker_x86_x86_64.profdata",
            },
        },
    },

    lto: {
        never: true,
    },
    pgo: {
        sampling: true,
    },
}

// ========================================================
// assorted modules
// ========================================================

sh_binary {
    name: "ldd",
    src: "ldd.sh",
    bazel_module: { bp2build_available: true },
}

// Used to generate binaries that can be backed by transparent hugepages.
cc_defaults {
    name: "linker_hugepage_aligned",
    arch: {
        arm64: {
            ldflags: ["-z max-page-size=0x200000"],
        },
        x86_64: {
            ldflags: ["-z max-page-size=0x200000"],
        },
    },
}

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-i686-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: {
        x86: {
            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
        },
        x86_64: {
            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
        },
    },

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

    name: "ld-android",
    defaults: ["linux_bionic_supported", "linker_version_script_overlay"],
    ramdisk_available: true,
    vendor_ramdisk_available: true,
    recovery_available: true,
    native_bridge_supported: true,

    nocrt: true,
    system_shared_libs: [],
    header_libs: ["libc_headers"],

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

    sanitize: {
        never: true,
    },

    apex_available: [
        "//apex_available:platform",
        "com.android.runtime",
    ],

    lto: {
        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_note_gnu_property_test.cpp",
        "linker_sleb128_test.cpp",
        "linker_utils_test.cpp",
        "linker_gnu_hash_test.cpp",

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

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

    arch: {
        arm: {
            srcs: ["arch/arm_neon/linker_gnu_hash_neon.cpp"],
        },
        arm64: {
            srcs: ["arch/arm_neon/linker_gnu_hash_neon.cpp"],
        },
    },
}

cc_benchmark {
    name: "linker-benchmarks",

    srcs: [
        "linker_gnu_hash_benchmark.cpp",
    ],

    arch: {
        arm: {
            srcs: ["arch/arm_neon/linker_gnu_hash_neon.cpp"],
        },
        arm64: {
            srcs: ["arch/arm_neon/linker_gnu_hash_neon.cpp"],
        },
    },
}