C++ Logo

std-proposals

Advanced search

[std-proposals] std::argc std::argv (available to global constructors)

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Tue, 13 Jun 2023 12:02:41 +0100
[ I tried to put this up on GodBolt and provide a link,
  but I gave up on the GNU inline assembler syntax,
  I just couldn't get it to work ]

Ever since C++ came out in 1979, there hasn't been any good reason why
the command line arguments to a program cannot be used as arguments to
the constructors of global objects.

I propose that in <cstdlib>, there will be:

    namespace std {
        extern int argc;
        extern char **argv;
    }

To implement this in my following example, the entry point to the
program will be 'entrypoint' instead of '_start', and the values of
'argc' and 'argv' will be gotten from the stack. The following syntax
is for the 'nasm' assembler:

    extern _ZSt4argc ; mangled name of std::argc (dword = 4 bytes)
    extern _ZSt4argv ; mangled name of std::argv (qword = 8 bytes)
    extern _start

    section .text
        global entrypoint:function
        entrypoint:
            push r15 ; callee-saved (we will restore it later)

            add rsp, 8 ; move the stack pointer to argc
            mov r15d, dword[rsp]
            mov dword[_ZSt4argc], r15d

            add rsp, 8 ; move the stack pointer to argv
            mov r15, rsp
            mov qword[_ZSt4argv], r15

            sub rsp, 16 ; move the stack pointer back to where we stored r15
            pop r15 ; restore the original value of r15 (callee-saved)
            jmp _start

So you compile this assembler as follows:

    nasm -o entrypoint.o -f elf64 entrypoint.asm

And then we build our program with:

    g++ -o prog main.cpp -no-pie entrypoint.o -e entrypoint

Here's an example program that works:

    #include <iostream>

    namespace std {
        int argc;
        char **argv;
    }

    class LaserController {
        int const grade;
        char model[16u];
    public:
        LaserController(int const arg_grade, char const *const arg_model)
          : grade(arg_grade)
        {
            if ( nullptr == arg_model ) { model[0u] = '\0'; return; }

            for ( unsigned i = 0u; i < sizeof(model); ++i )
            {
                model[i] = arg_model[i];
                if ( '\0' == model[i] ) break;
            }

            model[sizeof(model) - 1u] = '\0';
        }

        void Print(void)
        {
            std::cout << "Grade: " << grade << ", Model: " << model <<
std::endl;
        }
    };

    LaserController gLaser( std::argc, std::argv[ std::argc - 1u ] );

    int main(int argc, char **argv)
    {
        gLaser.Print();
    }

Received on 2023-06-13 11:02:53