Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #108115 > unrolled thread

main()

Started bybartc <bc@freeuk.com>
First post2017-04-14 00:53 +0100
Last post2017-04-14 13:49 -0400
Articles 15 — 11 participants

Back to article view | Back to comp.lang.c


Contents

  main() bartc <bc@freeuk.com> - 2017-04-14 00:53 +0100
    Re: main() Robert Wessel <robertwessel2@yahoo.com> - 2017-04-13 19:10 -0500
    Re: main() antispam@math.uni.wroc.pl - 2017-04-14 02:51 +0000
    Re: main() scott@slp53.sl.home (Scott Lurndal) - 2017-04-14 12:58 +0000
      Re: main() bartc <bc@freeuk.com> - 2017-04-14 14:11 +0100
        Re: main() Malcolm McLean <malcolm.mclean5@btinternet.com> - 2017-04-15 07:53 -0700
          Re: main() supercat@casperkitty.com - 2017-04-15 08:43 -0700
          Re: main() Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-04-15 16:50 +0100
          Re: main() Keith Thompson <kst-u@mib.org> - 2017-04-15 15:31 -0700
          Re: main() gordonb.y2etp@burditt.org (Gordon Burditt) - 2017-04-16 00:19 -0500
      The exec*() family (Was: main()) gazelle@shell.xmission.com (Kenny McCormack) - 2017-04-15 17:01 +0000
    Re: main() Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2017-04-14 10:04 -0400
      Re: main() bartc <bc@freeuk.com> - 2017-04-14 15:52 +0100
        Re: main() scott@slp53.sl.home (Scott Lurndal) - 2017-04-14 15:00 +0000
        Re: main() Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2017-04-14 13:49 -0400

#108115 — main()

Frombartc <bc@freeuk.com>
Date2017-04-14 00:53 +0100
Subjectmain()
Message-ID<ecUHA.285656$15.165152@fx07.am4>
I think this is not strictly part of the language but someone here may 
happen to know how it's done.

The arguments to a programs entry point such as main(int n, char** args) 
are not set up by the OS, but by some function the C implementation 
arranges.

On Windows at least, where such a function might use GetCommandLine() or 
__getmainargs() to obtain the command-line arguments and pass them to 
main().

What's the equivalent on Linux? Or will those args just magically be on 
the stack anyway? (Because after all Linux and C are very.. close.)

(I played around with code like this which possibly suggests the latter, 
but I need something definite. It seemed to work though!

[32-bit ARM]

#include <stdio.h>

int main(void) {
int i;
int n;
int *p=&i;
char** s;

for (i=0;i<10;++i) printf("%d: %d\n",i,*(p+i));

n=*(p+5);
s=(char**)*(p+4);

printf("N=%d\n",n);
for (i=0;i<n;++i) printf("%d: %s\n",i,s[i]);

}

)


-- 
bartc

[toc] | [next] | [standalone]


#108116

FromRobert Wessel <robertwessel2@yahoo.com>
Date2017-04-13 19:10 -0500
Message-ID<cg40fcp2lc6k7irgi3h25c7cf9np7taupg@4ax.com>
In reply to#108115
On Fri, 14 Apr 2017 00:53:59 +0100, bartc <bc@freeuk.com> wrote:

>I think this is not strictly part of the language but someone here may 
>happen to know how it's done.
>
>The arguments to a programs entry point such as main(int n, char** args) 
>are not set up by the OS, but by some function the C implementation 
>arranges.
>
>On Windows at least, where such a function might use GetCommandLine() or 
>__getmainargs() to obtain the command-line arguments and pass them to 
>main().
>
>What's the equivalent on Linux? Or will those args just magically be on 
>the stack anyway? (Because after all Linux and C are very.. close.)
>
>(I played around with code like this which possibly suggests the latter, 
>but I need something definite. It seemed to work though!
>
>[32-bit ARM]
>
>#include <stdio.h>
>
>int main(void) {
>int i;
>int n;
>int *p=&i;
>char** s;
>
>for (i=0;i<10;++i) printf("%d: %d\n",i,*(p+i));
>
>n=*(p+5);
>s=(char**)*(p+4);
>
>printf("N=%d\n",n);
>for (i=0;i<n;++i) printf("%d: %s\n",i,s[i]);
>
>}
>
>)



I can't tell you how it works for ARM, but in x86-32 Linux, the entry
point to the loaded module (as specified in the ELF header), has three
items on the stack (argc and the argv and env pointers).  Remember
that in *nix, the shell expands the command line arguments, not the
application (as in Windows).  That entry point is somewhere in the crt
(crtbegin.o, crtend.o, gcrt1.o), which does some stuff needed for
startup, and then eventually calls main().

[toc] | [prev] | [next] | [standalone]


#108117

Fromantispam@math.uni.wroc.pl
Date2017-04-14 02:51 +0000
Message-ID<ocpdff$sci$1@z-news.wcss.wroc.pl>
In reply to#108115
bartc <bc@freeuk.com> wrote:
> I think this is not strictly part of the language but someone here may 
> happen to know how it's done.
> 
> The arguments to a programs entry point such as main(int n, char** args) 
> are not set up by the OS, but by some function the C implementation 
> arranges.
> 
> On Windows at least, where such a function might use GetCommandLine() or 
> __getmainargs() to obtain the command-line arguments and pass them to 
> main().
> 
> What's the equivalent on Linux? Or will those args just magically be on 
> the stack anyway? (Because after all Linux and C are very.. close.)

In Linux program initialization (startup) is shared responsibility
of compiler, kernel, libc and dynamic linker.  Linux executable has field
pointing to "ELF interpeter", that is program resposible for
initialization of dynamic linking.  libc also may need some initalization.
If you properly plug your object files into the framwork, then
your main will get called with correct arguments.  Otherwise you
risk crashes due to wrong initialization.  To the point: on
Debian x86_64 libc provides 'crt1.o' which contains startup
routine called '_start'.  This routine may look trivial (it is
just doing little register manipulations and then calls 'main').
But you need to do all required woodoo.  Case in point: I was
using a Modula 2 compiler and on new version of Linux executables
from this compiler begun to crash.  I looked at the problem and
the Modula 2 compiler provided its own startup routine which
turned out to be incompatible with newer version of Linux.

Arguments to main are provided by kernel, I did not check if
they are passed on the stack or in registers (details depend
on architecture).  But if you want to use libc you need to
initialize things in way required by libc.

-- 
                              Waldek Hebisch

[toc] | [prev] | [next] | [standalone]


#108128

Fromscott@slp53.sl.home (Scott Lurndal)
Date2017-04-14 12:58 +0000
Message-ID<dI3IA.10330$sn6.1876@fx44.iad>
In reply to#108115
bartc <bc@freeuk.com> writes:
>I think this is not strictly part of the language but someone here may 
>happen to know how it's done.
>
>The arguments to a programs entry point such as main(int n, char** args) 
>are not set up by the OS, but by some function the C implementation 
>arranges.
>
>On Windows at least, where such a function might use GetCommandLine() or 
>__getmainargs() to obtain the command-line arguments and pass them to 
>main().
>
>What's the equivalent on Linux? Or will those args just magically be on 
>the stack anyway? (Because after all Linux and C are very.. close.)
>

Unix and unix-like systems get the arguments from the system
call used to create the process.   Typically this is one of
the exec-family of system calls.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/execv.html

The path argument provides the cwd-relative (or absolute) path to
the ELF (or COFF in the olden days) binary.   The ELF header has
a field which records the virtual address of the entry point.  That
virtual address refers (generally) to the label _start in in the
c-runtime initialization code, which handles various pre-main setup
activities then invokes main with the following signature:

  int main(int argc, const char **argv, const char **envp, Elf32_auxv_t **auxv)

envp contains a list of all exported environment variables and their
values.   auxv conveys information from the run-time ELF loader.

http://articles.manugarg.com/aboutelfauxiliaryvectors

[toc] | [prev] | [next] | [standalone]


#108129

Frombartc <bc@freeuk.com>
Date2017-04-14 14:11 +0100
Message-ID<bU3IA.457701$4n3.358291@fx14.am4>
In reply to#108128
On 14/04/2017 13:58, Scott Lurndal wrote:
> bartc <bc@freeuk.com> writes:

>> What's the equivalent on Linux? Or will those args just magically be on
>> the stack anyway? (Because after all Linux and C are very.. close.)
>>
>
> Unix and unix-like systems get the arguments from the system
> call used to create the process.   Typically this is one of
> the exec-family of system calls.
>
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/execv.html
>
> The path argument provides the cwd-relative (or absolute) path to
> the ELF (or COFF in the olden days) binary.   The ELF header has
> a field which records the virtual address of the entry point.  That
> virtual address refers (generally) to the label _start in in the
> c-runtime initialization code, which handles various pre-main setup
> activities then invokes main with the following signature:
>
>   int main(int argc, const char **argv, const char **envp, Elf32_auxv_t **auxv)
>
> envp contains a list of all exported environment variables and their
> values.   auxv conveys information from the run-time ELF loader.

Interesting, I didn't know main() could take extra parameters. On 
Windows (as I don't have a handy Linux at the minute) this works:

#include <stdio.h>
#include <stdlib.h>

int main(int n, char** args, char** env) {
int i;

for (i=0; i<n; ++i)
|   printf("%d: %s\n",i,args[i]);

while (**env) {
|   printf("Env str: %s\n",*env);
|   *env += strlen(*env)+1;
}

}

-- 
bartc

[toc] | [prev] | [next] | [standalone]


#108159

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2017-04-15 07:53 -0700
Message-ID<f8634432-85fa-43f8-b4f6-37114705386b@googlegroups.com>
In reply to#108129
On Friday, April 14, 2017 at 2:11:42 PM UTC+1, Bart wrote:
> On 14/04/2017 13:58, Scott Lurndal wrote:
> 
> > envp contains a list of all exported environment variables and their
> > values.   auxv conveys information from the run-time ELF loader.
> 
> Interesting, I didn't know main() could take extra parameters. On 
> Windows (as I don't have a handy Linux at the minute) this works:
> 
> #include <stdio.h>
> #include <stdlib.h>
> 
> int main(int n, char** args, char** env) {
> int i;
> 
> for (i=0; i<n; ++i)
> |   printf("%d: %s\n",i,args[i]);
> 
> while (**env) {
> |   printf("Env str: %s\n",*env);
> |   *env += strlen(*env)+1;
> }
> 
> }
> 
Exactly.
envp is one of those things which probably should be in the standard but
isn't, as many programs need the environment variables.
Having said that, setting environment variables is a horrid thing to
require of a user.

[toc] | [prev] | [next] | [standalone]


#108160

Fromsupercat@casperkitty.com
Date2017-04-15 08:43 -0700
Message-ID<6ea9ebed-9832-43d3-bf6b-8d39ce4148d3@googlegroups.com>
In reply to#108159
On Saturday, April 15, 2017 at 9:53:11 AM UTC-5, Malcolm McLean wrote:
> Exactly.
> envp is one of those things which probably should be in the standard but
> isn't, as many programs need the environment variables.
> Having said that, setting environment variables is a horrid thing to
> require of a user.

Many programs are invoked using commands typed in a shell or shell-escape
prompt, and requiring users to re-specify common options every time they
type commands is apt to be a nuisance.  While command shells could offer
macro facilities to minimize such retyping, it would be hard to make such
macros effective in programs that have a "shell-escape" feature to run
outside programs.

[toc] | [prev] | [next] | [standalone]


#108161

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-04-15 16:50 +0100
Message-ID<87mvbhpt4n.fsf@bsb.me.uk>
In reply to#108159
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Friday, April 14, 2017 at 2:11:42 PM UTC+1, Bart wrote:
>> On 14/04/2017 13:58, Scott Lurndal wrote:
>> 
>> > envp contains a list of all exported environment variables and their
>> > values.   auxv conveys information from the run-time ELF loader.
>> 
>> Interesting, I didn't know main() could take extra parameters. On 
>> Windows (as I don't have a handy Linux at the minute) this works:
>> 
>> #include <stdio.h>
>> #include <stdlib.h>
>> 
>> int main(int n, char** args, char** env) {
>> int i;
>> 
>> for (i=0; i<n; ++i)
>> |   printf("%d: %s\n",i,args[i]);
>> 
>> while (**env) {
>> |   printf("Env str: %s\n",*env);
>> |   *env += strlen(*env)+1;
>> }
>> 
>> }
>> 
> Exactly.
> envp is one of those things which probably should be in the standard but
> isn't, as many programs need the environment variables.

The standard includes getenv for that.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#108166

FromKeith Thompson <kst-u@mib.org>
Date2017-04-15 15:31 -0700
Message-ID<lnh91ptiag.fsf@kst-u.example.com>
In reply to#108159
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
[...]
> Exactly.
> envp is one of those things which probably should be in the standard but
> isn't, as many programs need the environment variables.

POSIX has `extern char **environ;`.  And of course standard C has
getenv(), which isn't as flexible (you can only get the value of an
environment variable if you already know its name, but that's usually
enough).

> Having said that, setting environment variables is a horrid thing to
> require of a user.

Balderdash.  (And in may cases, environment variables are set by the
environment, not explicitly by the user.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#108168

Fromgordonb.y2etp@burditt.org (Gordon Burditt)
Date2017-04-16 00:19 -0500
Message-ID<vcSdnaH5TfVRY2_FnZ2dnUU7-XnNnZ2d@posted.internetamerica>
In reply to#108159
> envp is one of those things which probably should be in the standard but
> isn't, as many programs need the environment variables.

Many programs need specific environment variables (They know the
names of them, like "HOME" or "PATH" or whatever ahead of time).

There are only a few that need to be able to look at *ALL* of the
environment variables, without knowing names ahead of time.  One
of them is the UNIX "env" program which among other functions, lists
all of them.

Mostly, these are programs that invoke other programs, and want to
pass on all the environment variables they were given, perhaps with
a few changes.  That want often proves to be a security hole.

> Having said that, setting environment variables is a horrid thing to
> require of a user.

Environment variables are often used to communicate between parts
of a collection of programs.  The user doesn't have to mess with
these.

[toc] | [prev] | [next] | [standalone]


#108163 — The exec*() family (Was: main())

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2017-04-15 17:01 +0000
SubjectThe exec*() family (Was: main())
Message-ID<octjld$6m1$1@news.xmission.com>
In reply to#108128
In article <dI3IA.10330$sn6.1876@fx44.iad>,
Scott Lurndal <slp53@pacbell.net> wrote:
...
>Unix and unix-like systems get the arguments from the system
>call used to create the process.   Typically this is one of
>the exec-family of system calls.
>
>http://pubs.opengroup.org/onlinepubs/9699919799/functions/execv.html

Keep in mind that, on Linux at least (and also OSX, but I don't know about
other Unixes), there is only one exec*() system call - namely, execve(2).
All the others (which are all in section 3, not section 2) are "front ends"
to execve().

-- 
The randomly chosen signature file that would have appeared here is more than 4
lines long.  As such, it violates one or more Usenet RFCs.  In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
	http://user.xmission.com/~gazelle/Sigs/TedCruz

[toc] | [prev] | [next] | [standalone]


#108130

FromLew Pitcher <lew.pitcher@digitalfreehold.ca>
Date2017-04-14 10:04 -0400
Message-ID<ocqkob$jrl$1@dont-email.me>
In reply to#108115
bartc wrote:

> I think this is not strictly part of the language but someone here may
> happen to know how it's done.
> 
> The arguments to a programs entry point such as main(int n, char** args)
> are not set up by the OS, but by some function the C implementation
> arranges.
> 
> On Windows at least, where such a function might use GetCommandLine() or
> __getmainargs() to obtain the command-line arguments and pass them to
> main().
> 
> What's the equivalent on Linux? Or will those args just magically be on
> the stack anyway? (Because after all Linux and C are very.. close.)

In Linux, as in all Unix-like operating systems, the arguments ultimately 
passed to main() as argv come from the invocation of one of the exec() 
system functions.

Those functions accept (in one form or another)
- a pointer to string that provides a filesystem path to the executable, and
- a list of pointers to strings, that each provide a value for the
  corresponding argv[] element (including argv[0]).

The OS ensures that the strings pointed to by the exec() call are copied to 
known, standard locations in the memory map of the new process, and builds 
the corresponding argc and argv[] arrays /before/ loading and invoking the 
program code and C runtime startup.

So, yes, those args "just magically" appear, as far as the new process is 
concerned, just as the code and data of that new process "just magically" 
appear in memory. 


-- 
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

[toc] | [prev] | [next] | [standalone]


#108131

Frombartc <bc@freeuk.com>
Date2017-04-14 15:52 +0100
Message-ID<nm5IA.358993$9O7.177093@fx22.am4>
In reply to#108130
On 14/04/2017 15:04, Lew Pitcher wrote:
> bartc wrote:
>
>> I think this is not strictly part of the language but someone here may
>> happen to know how it's done.
>>
>> The arguments to a programs entry point such as main(int n, char** args)
>> are not set up by the OS, but by some function the C implementation
>> arranges.
>>
>> On Windows at least, where such a function might use GetCommandLine() or
>> __getmainargs() to obtain the command-line arguments and pass them to
>> main().
>>
>> What's the equivalent on Linux? Or will those args just magically be on
>> the stack anyway? (Because after all Linux and C are very.. close.)
>
> In Linux, as in all Unix-like operating systems, the arguments ultimately
> passed to main() as argv come from the invocation of one of the exec()
> system functions.
>
> Those functions accept (in one form or another)
> - a pointer to string that provides a filesystem path to the executable, and
> - a list of pointers to strings, that each provide a value for the
>   corresponding argv[] element (including argv[0]).
>
> The OS ensures that the strings pointed to by the exec() call are copied to
> known, standard locations in the memory map of the new process, and builds
> the corresponding argc and argv[] arrays /before/ loading and invoking the
> program code and C runtime startup.
>
> So, yes, those args "just magically" appear, as far as the new process is
> concerned, just as the code and data of that new process "just magically"
> appear in memory.

I said is was magical because the order of those parameters seems to 
match the parameters as used in C's main() function.

Either it's an amazing coincidence or one came first and the other 
copied. That may or may not been a sensible thing to do, but it makes it 
harder to disentangle what is C, and what is OS.

-- 
bartc

[toc] | [prev] | [next] | [standalone]


#108132

Fromscott@slp53.sl.home (Scott Lurndal)
Date2017-04-14 15:00 +0000
Message-ID<2u5IA.7544$uf1.7205@fx40.iad>
In reply to#108131
bartc <bc@freeuk.com> writes:
>On 14/04/2017 15:04, Lew Pitcher wrote:

>Either it's an amazing coincidence or one came first and the other 
>copied. That may or may not been a sensible thing to do, but it makes it 
>harder to disentangle what is C, and what is OS.

Which is hardly suprising, given the history of the development
of C (which was developed as the language for Unix kernel
and operating system utility development
some decade or more before Windows existed).

[toc] | [prev] | [next] | [standalone]


#108140

FromLew Pitcher <lew.pitcher@digitalfreehold.ca>
Date2017-04-14 13:49 -0400
Message-ID<ocr1u7$a3l$1@dont-email.me>
In reply to#108131
bartc wrote:

> On 14/04/2017 15:04, Lew Pitcher wrote:
>> bartc wrote:
>>
>>> I think this is not strictly part of the language but someone here may
>>> happen to know how it's done.
>>>
>>> The arguments to a programs entry point such as main(int n, char** args)
>>> are not set up by the OS, but by some function the C implementation
>>> arranges.
>>>
>>> On Windows at least, where such a function might use GetCommandLine() or
>>> __getmainargs() to obtain the command-line arguments and pass them to
>>> main().
>>>
>>> What's the equivalent on Linux? Or will those args just magically be on
>>> the stack anyway? (Because after all Linux and C are very.. close.)
>>
>> In Linux, as in all Unix-like operating systems, the arguments ultimately
>> passed to main() as argv come from the invocation of one of the exec()
>> system functions.
>>
>> Those functions accept (in one form or another)
>> - a pointer to string that provides a filesystem path to the executable,
>> and - a list of pointers to strings, that each provide a value for the
>>   corresponding argv[] element (including argv[0]).
>>
>> The OS ensures that the strings pointed to by the exec() call are copied
>> to known, standard locations in the memory map of the new process, and
>> builds the corresponding argc and argv[] arrays /before/ loading and
>> invoking the program code and C runtime startup.
>>
>> So, yes, those args "just magically" appear, as far as the new process is
>> concerned, just as the code and data of that new process "just magically"
>> appear in memory.
> 
> I said is was magical because the order of those parameters seems to
> match the parameters as used in C's main() function.
> 
> Either it's an amazing coincidence

It's not a coincidence

> or one came first and the other copied.

And, that's not what happened either.

C was developed as the high-level language to implement Unix with. Unix was 
originally developed in assembly language, then rewritten in C. It is by 
design that the C language, the C runtime support, the Unix runtime support, 
the Unix OS system calls, and the underlying Unix OS all work together to 
"magically" place arguments seeded by an exec() syscall into known locations 
in memory so that the executable initiated by the exec() syscall can locate 
them and populate the C main() argc and argv (and envp) parameters.

> That may or may not been a sensible thing to do, but it makes it
> harder to disentangle what is C, and what is OS.

I guess so, but only in that those OS that do not provide the requisite 
features natively must do so by emulation.

-- 
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web