将普通的二进制文件绑定到可解除的

发布于 2025-01-30 01:24:51 字数 192 浏览 3 评论 0原文

以下问题与实际问题无关,但我只是好奇:
如何将整个文件与可执行文件链接并在C / C ++中获取该块的起始地址和大小?有时,拥有一个可执行文件,其中包含一些归因性,这些归因于通常是在运行时读取的外部文件。
任何与任何编译器系统或平台相关的示例都将不胜感激。
除此之外 我故意不使用与特定语言有关的任何标签发布此问题,而只是与与特定实现相关的标签。

The following question isn't related to an actual problem but what I just was curious about:
How can I link a whole file with an executable and get the starting address and size of that block at runtime in C / C++ ? Sometimes it would be nice to have a single executable which contains some resorces which conventionally would be external files to be read at runtime.
Any examples related to any compiler system or platform would be appreciated.
Aside from that it would be nice to have standard means in C / C++ to do that.
I intentionally don't post this questions with any tag related to specific languages but just with tags that are related to specific implementations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

茶色山野 2025-02-06 01:24:51

由于没有适当的答案,所以我写了一些C ++ 20程序,将文件转换为带有未签名的char数组和一个带有此数组的声明的标题文件的C文件。
第一个参数是要成为数组的文件,第二个参数是没有扩展名的输出文件的名称,第三个参数是数组的名称,并且有一个可选的第四参数,每行字节数,默认为16。

#include <iostream>
#include <fstream>
#include <vector>
#include <charconv>
#include <string_view>

using namespace std;

int main( int argc, char **argv )
{
    try
    {
        if( argc < 4 )
            return EXIT_FAILURE;
        size_t bytesPerLine = 16;
        char const
            *inFile = argv[1],
            *outFile = argv[2],
            *symbolName = argv[3],
            *sBytesPerLine = argc >= 5 ? argv[4] : nullptr;
        if( sBytesPerLine )
        {
            from_chars_result fcr = from_chars( sBytesPerLine, sBytesPerLine + strlen( argv[3] ), bytesPerLine );
            if( fcr.ec != errc() || *fcr.ptr )
                throw invalid_argument( "number of bytes per line format error" );
        }
        ifstream ifs;
        ifs.exceptions( ifstream::failbit | ifstream::badbit );
        ifs.open( inFile, ifstream::in | ifstream::binary );
        ifs.seekg( 0, ifstream::end );
        streampos spSize = ifs.tellg();
        if( spSize > (size_t)-1 )
            throw invalid_argument( "file too large" );
        size_t size = (size_t)spSize;
        if( !size )
            return EXIT_FAILURE;
        using vc_t = vector<char>;
        using vc_it = typename vc_t::iterator;
        vc_t data( size, 0 );
        ifs.seekg( 0, ifstream::beg );
        ifs.read( data.data(), (streamsize)size );
        ofstream ofsHeader, ofsC;
        auto writeDelcaration = [&]( ofstream &ofs, bool definition )
        {
            ofs.exceptions( ofstream::failbit | ofstream::badbit );
            ofs.open( string( string( outFile ) + (!definition ? ".h" : ".c") ).c_str(), ofstream::out | ofstream::trunc | ofstream::binary );
            ofs << (!definition ? "extern " : "") << "unsigned char const " << symbolName << "[" << data.size() << "]" << (!definition ? ";" : " = ") << endl;;
        };
        writeDelcaration( ofsHeader, false );
        writeDelcaration( ofsC, true );
        ofsC << "{" << endl;
        string bulk;
        auto writeBulk = [&]<typename AppendFn>( AppendFn appendFn )
            requires requires( AppendFn appendFn, string_view const &sv ) { { appendFn( sv ) }; }
        {
            size_t remaining = data.size(), bytesInLine;
            for( vc_it cIt = data.begin(); remaining; remaining -= bytesInLine )
            {
                bytesInLine = remaining >= bytesPerLine ? bytesPerLine : remaining;
                appendFn( "\t" );
                for( size_t b = 0; b != bytesInLine; ++b )
                {
                    char hex[2 + 2 + 2 + 1];
                    memcpy( hex, "0x", 2 );
                    unsigned char byte = cIt[b];
                    auto toHexChar = []( unsigned char c ) -> char { return c < 10 ? c + '0' : c - 10 + 'A'; };
                    for( size_t i = 2; i--; byte >>= 4 )
                        hex[2 + i] = toHexChar( byte & 0xF );
                    size_t nChars = 4;
                    if( b + 1 != bytesInLine )
                        memcpy( hex + 2 + 2, ", ", 2 ),
                        nChars += 2;
                    else
                        if( b + 1 < remaining )
                            hex[2 + 2] = ',',
                            ++nChars;
                    appendFn( string_view( hex, nChars ) );
                }
                cIt += bytesInLine;
                appendFn( "\n" );
            }
        };
        size_t bulkLength = 0;
        writeBulk( [&]( string_view const &sv ) { bulkLength += sv.length(); } );
        bulk.reserve( bulkLength );
        writeBulk( [&]( string_view const &sv ) { bulk += sv; } );
        ofsC << bulk;
        ofsC << "};" << endl;
    }
    catch( exception const &exc )
    {
        cout << exc.what() << endl;
    }
}

写作所有 to 直接流太慢,因此散装。
编译较大文件的输出可能真的很慢,但是输出的C-part通常并不是项目中其他文件的任何依赖性。

As there was no proper answer I wrote a little C++20-program that converts a file to a C-file with a unsigned char array and a header file with just the declaration of this array.
The first parameter is the file to become the array, the second parameter is the name of the output-files without an extension, the third parameter is the name of the array and there's an optional fourth parameter with the number of bytes per line, which is defaulted to 16.

#include <iostream>
#include <fstream>
#include <vector>
#include <charconv>
#include <string_view>

using namespace std;

int main( int argc, char **argv )
{
    try
    {
        if( argc < 4 )
            return EXIT_FAILURE;
        size_t bytesPerLine = 16;
        char const
            *inFile = argv[1],
            *outFile = argv[2],
            *symbolName = argv[3],
            *sBytesPerLine = argc >= 5 ? argv[4] : nullptr;
        if( sBytesPerLine )
        {
            from_chars_result fcr = from_chars( sBytesPerLine, sBytesPerLine + strlen( argv[3] ), bytesPerLine );
            if( fcr.ec != errc() || *fcr.ptr )
                throw invalid_argument( "number of bytes per line format error" );
        }
        ifstream ifs;
        ifs.exceptions( ifstream::failbit | ifstream::badbit );
        ifs.open( inFile, ifstream::in | ifstream::binary );
        ifs.seekg( 0, ifstream::end );
        streampos spSize = ifs.tellg();
        if( spSize > (size_t)-1 )
            throw invalid_argument( "file too large" );
        size_t size = (size_t)spSize;
        if( !size )
            return EXIT_FAILURE;
        using vc_t = vector<char>;
        using vc_it = typename vc_t::iterator;
        vc_t data( size, 0 );
        ifs.seekg( 0, ifstream::beg );
        ifs.read( data.data(), (streamsize)size );
        ofstream ofsHeader, ofsC;
        auto writeDelcaration = [&]( ofstream &ofs, bool definition )
        {
            ofs.exceptions( ofstream::failbit | ofstream::badbit );
            ofs.open( string( string( outFile ) + (!definition ? ".h" : ".c") ).c_str(), ofstream::out | ofstream::trunc | ofstream::binary );
            ofs << (!definition ? "extern " : "") << "unsigned char const " << symbolName << "[" << data.size() << "]" << (!definition ? ";" : " = ") << endl;;
        };
        writeDelcaration( ofsHeader, false );
        writeDelcaration( ofsC, true );
        ofsC << "{" << endl;
        string bulk;
        auto writeBulk = [&]<typename AppendFn>( AppendFn appendFn )
            requires requires( AppendFn appendFn, string_view const &sv ) { { appendFn( sv ) }; }
        {
            size_t remaining = data.size(), bytesInLine;
            for( vc_it cIt = data.begin(); remaining; remaining -= bytesInLine )
            {
                bytesInLine = remaining >= bytesPerLine ? bytesPerLine : remaining;
                appendFn( "\t" );
                for( size_t b = 0; b != bytesInLine; ++b )
                {
                    char hex[2 + 2 + 2 + 1];
                    memcpy( hex, "0x", 2 );
                    unsigned char byte = cIt[b];
                    auto toHexChar = []( unsigned char c ) -> char { return c < 10 ? c + '0' : c - 10 + 'A'; };
                    for( size_t i = 2; i--; byte >>= 4 )
                        hex[2 + i] = toHexChar( byte & 0xF );
                    size_t nChars = 4;
                    if( b + 1 != bytesInLine )
                        memcpy( hex + 2 + 2, ", ", 2 ),
                        nChars += 2;
                    else
                        if( b + 1 < remaining )
                            hex[2 + 2] = ',',
                            ++nChars;
                    appendFn( string_view( hex, nChars ) );
                }
                cIt += bytesInLine;
                appendFn( "\n" );
            }
        };
        size_t bulkLength = 0;
        writeBulk( [&]( string_view const &sv ) { bulkLength += sv.length(); } );
        bulk.reserve( bulkLength );
        writeBulk( [&]( string_view const &sv ) { bulk += sv; } );
        ofsC << bulk;
        ofsC << "};" << endl;
    }
    catch( exception const &exc )
    {
        cout << exc.what() << endl;
    }
}

Writing everything to directly a stream was too slow, therefore the bulk-string.
Compiling the output of a larger file can be really slow but the C-part of the output usually isn't any dependency of other files in the project.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文