C++ Logo

std-proposals

Advanced search

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

From: Tom Honermann <tom_at_[hidden]>
Date: Tue, 13 Jun 2023 07:41:19 -0400
This is being pursued as WG14 N2948 (Accessing the command line
arguments outside of main())
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2948.pdf>.

Tom.

On 6/13/23 7:02 AM, Frederick Virchanza Gotham via Std-Proposals wrote:
> [ 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:41:20