Loading...
/*
 * Copyright (c) 2024 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 *
 * @APPLE_LICENSE_HEADER_END@
 */

#include <stddef.h>
#include <fcntl.h>
#include <unistd.h>

// mach_o
#include "Header.h"
#include "Architecture.h"

// mach_o_writer
#include "HeaderWriter.h"

#include "MemoryBuffer.h"

#include "cctools_helpers.h"


using mach_o::Header;
using mach_o::HeaderWriter;
using mach_o::Error;
using mach_o::Architecture;

VIS_HIDDEN
void make_obj_file_with_linker_options(uint32_t cpu_type, uint32_t cpu_subtype,
                                       uint32_t libHintCount, const char* libNames[],
                                       uint32_t frameworkHintCount, const char* frameworkNames[],
                                       char outPath[PATH_MAX])
{
    // estimate total load command size
    Architecture arch(cpu_type, cpu_subtype);
    uint32_t size = sizeof(mach_header_64);
    for (uint32_t i=0; i < libHintCount; ++i)
        size += Header::pointerAligned(arch.is64(), (uint32_t)(sizeof(linker_option_command) + strlen(libNames[i]) + 3));
    for (uint32_t i=0; i < frameworkHintCount; ++i)
        size += Header::pointerAligned(arch.is64(), (uint32_t)(sizeof(linker_option_command) + strlen(frameworkNames[i]) + 12));
    size_t allocationSize = (size + 0x3FFF) & (-0x4000);
    // create HeaderWriter
    WritableMemoryBuffer mhBuffer = WritableMemoryBuffer::allocate(allocationSize);
    HeaderWriter* mh = HeaderWriter::make(mhBuffer, MH_OBJECT, 0, arch, false);
    // add all auto-linking load commands
    for (uint32_t i=0; i < libHintCount; ++i) {
        const char* libName     = libNames[i];
        size_t      libBuffSize = strlen(libName) + 3; // space for -l and trailing nul
        char        libBuffer[libBuffSize];
        strlcpy(libBuffer, "-l", libBuffSize);
        strlcat(libBuffer, libName, libBuffSize);
        std::span<uint8_t> buffer{(uint8_t*)libBuffer, libBuffSize};
        mh->addLinkerOption(buffer, 1);
    }
    for (uint32_t i=0; i < frameworkHintCount; ++i) {
        const char* fwName     = frameworkNames[i];
        size_t      fwBuffSize = strlen(fwName) + 12;  // space for -framework and trailing nul
        char        fwBuffer[fwBuffSize];
        strcpy(&fwBuffer[0],  "-framework");
        strcpy(&fwBuffer[11], fwName);
        std::span<uint8_t> buffer{(uint8_t*)fwBuffer, fwBuffSize};
        mh->addLinkerOption(buffer, 2);
    }

    mh->save(outPath);
}