Where do argc and argv come from?
briancallahan.net
briancallahan.net
There are a few auxiliary vector keys that are standard per-ELF, and others that are platform-specific. The original purpose of the auxv was to provide the ELF interpreter (ld.so) with information it needs in order to bootstrap.
I was surprised to discover a.out support is still there in the kernel [1]. There has been talk on LKML about whether to remove it [2] – apparently it has accumulated regression bugs (particularly in the area of core dumping) which nobody has noticed and fixed, which is the inevitable fate of code that hangs around for decades after everybody stops using it – but it still hasn't been removed yet.
[1] https://github.com/torvalds/linux/blob/master/fs/binfmt_aout...
However, it is not part of standard C or POSIX/SUS.
It should be:
char **envThanks for sharing
arg(ument) c(ount) and arg(ument) v(ector) is what I was taught.
edit: After a re-read, the article is about where the actual values come from and not the historical semantic meaning of the variable names.
I have written bugs because of this.
def only_positional(a, b, /):
Pass
Similarly, you can prevent keyword args from being called as positional (which has the inverse problem of breaking client code by changing the order of keyword arguments): def only_keyword(*, foo, bar):
passIt makes it so that certain built-ins and native APIs can be properly typed, sure, but positional/keyword interchangeability is arguably a violation of the Zen, too.
That said, I love Python and it's the language that I taught to my daughters first.
The only thing that might trip up beginners in Go is error handling but if they haven't learned any other way of doing it before then they might just accept it for what it is.
On the other hand, stuff like tabs vs spaces - when you would expect this to even come up? Whatever editor they'd use to start coding with, it'll be configured to use one or the other. In fact, these days, unless you get something exotic, it'll be spaces for sure.
And Python has exactly two ways to write a loop: one for conditional looping, and another when you want to iterate over a collection or a range. Is that really too many?
For example, the question "how does `x.y()` get evaluated?" has a very complex answer. `x += y` is even more complex.
For a real deep understanding, you'd probably have to jump into the actual computer microchip architecture to learn how computers store memory and do things like pipelining, branch prediction, and caching. Then a primer on Operating Systems (I like "Three Easy Pieces") should fill in the gaps.
Does anyone know if that is still the case for recent versions of Angular?
In Swift the argument labels are the same as the argument names by default, but you can also supply different values for them.
E.g. these days the Spring framework defaults to using the parameter name as the qualifying name to discriminate between otherwise identical types during autowiring.
In most cases, Ruby handles this capture via a double-splat operator in the parameter list.
However, Ruby itself does have both positional and named method parameters. The former contribute to arity and may be overridden and renamed in subclasses, and this remains true for Rails methods accepting positional arguments.
It is also the case that a hash is implicitly congruent to named arguments, although this is controversial and may change in future. I’m sorry to report that no-one has ever described this as “arg hash” or “argh” for short.
I jumped straight into Chapter 7: Linking and learned so much that I read a bunch of other chapters for the fun of it. E.g., Chapter 7 covered that the `_start` symbol mentioned in this post is just a symbol in your executable that the Linux executable loader knows to jump to, but it's not the only special symbol!
The chapter on linking also covered how loading and linking dynamic/shared libraries works, which was also really cool. I wrote up some of the things I learned about that stuff too.[2]
Chromium, for example, does this: https://source.chromium.org/chromium/chromium/src/+/master:s...
From the foregoing progression it can be inferred that this idiom was common and deemed a Good Thing by some faction in computer science of the time.
As for functions with specific names, when linking against libraries there are typically symbol tables for resolving references between separately compiled modules.
As a self-professed (I took out a small display ad in the print publications _Computer World_ and _Asian Computing Monthly_ in 1984) "VAX Hacker for Hire", I made use of C's utter lack of concern for such things by declaring a char* arg and using pointer arithmetic to get the actual count of args to implement optional parameters; I wasn't the only one. Between that and abusing the REF and VAL pragmas in pretty much all DEC programming languages, it was good times.
What did that cost? And was it effective in getting you projects?
2) Yes, I did make the acquaintance of a local (!) company, which I ended up having a 10 year relationship with. I also had a few of entertaining inquiries, none of which got me in trouble with the law, but also didn't make me any money. (Know when to say "no".)
The commandline is stored in the process environment block and can be set to anything when the process is created.
You then pass it into https://docs.microsoft.com/en-us/windows/win32/api/shellapi/... to get it split out if you need it.
I can see why they did it that way. No reason to waste cycles on something if you do not need it. Though most frameworks go and call it for you anyway these days.
- https://web.archive.org/web/20200128073602/http://www.window...
- https://web.archive.org/web/20191119112915/https://blogs.msd...
* mainCRTStartup
* wmainCRTStartup
* WinMainCRTStartup
* wWinMainCRTStartup
Conveniently these all have the exact same function signature (i.e. the real entry point signature). For example:
extern "C" int WinMainCRTStartup()
Although obviously the C runtime implementations differ for each of the listed entry points.You can also set what it is using that compiler option if you want. You usually do not want to as the default versions do quite a bit of stuff. I think the winmain one was the 3.x default. But changed when they added in other bits (I want to say threading, and console setup but I could be wrong).
Windows is a weird one as it has this odd DOS/VMS/OS2/Win16/32 heritage so entry into the program is one that has some bagage. Winmain is one of those leftovers. The params passed in need to use the functions associated to them.
My advice is always with this stuff. read the docs. There is a ton of info in there. It is kind of picky to get just right.
That could be the superior option. Moving command line expansion into a shared library gets rid of the problem where the command line with globs expanded is too long, could have standardized option handling earlier (that system-provided library for globbing could easily grow to handle option flags), could better handle file names containing spaces, etc.
https://docs.microsoft.com/en-us/cpp/c-runtime-library/argc-...
And if you are building the app with the C runtime, you may as well just use regular main().
The application can then do whatever it likes with the string. Sure you can use an entry point that parses the arguments in different ways but that's still the application parsing the string. You're just using a library function to do the parsing instead of doing it manually.
At no point does "Windows" do anything. As far as its concerned it's just a string being passed in at process creation.
I suspect you're really talking about linking to setargv.obj?
_start:
popq %rdi
movq %rsp, %rdi
callq main
the second %rdi should be %rsi, which is confirmed by the explanatory test:> If it's really that easy all we will need to do is add movq %rsp, %rsi after the popq %rdi we just added.
EDIT: now fixed
http://dbp-consulting.com/tutorials/debugging/linuxProgramSt... mentions something really fun after envp, which is the ELF auxillary info, including a random seed offered by the kernel to seed rand if you want it.
int main(int argc, char **argv, char **envp)https://en.wikipedia.org/wiki/Crt0
So it's not really part of the "compiler" itself, it's usually an object file the linker includes in the linking job on your behalf.
[0] https://github.com/lpsantil/rt0/blob/master/src/lib/00_start...
"/usr/bin/ld" --hash-style=both --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/9/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/9 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../.. -L/usr/lib/llvm-9/bin/../lib -L/lib -L/usr/lib /tmp/test-4e14b0.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
Breaking it out in pieces, your code comes from:* /usr/lib/x86_64-linux-gnu/crt1.o -- This file contains the "beginning" of your executable, and the definition of _start (the entry point to your entire application).
* /usr/lib/x86_64-linux-gnu/crti.o -- This contains the beginning of the .init and .fini instructions, which include the glue code for calling static initializers and destructors. This is more specifically linker magic to trigger ELF magic headers.
* /usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o -- More glue code for static initializers and destructors. There are a few different approaches to implementing static initializers that varies on a per-compiler basis.
* /tmp/test-4e14b0.o -- Your code! When you specify multiple object files, or multiple libraries, all of those links get dropped in this location.
* -lgcc, -lgcc_s -- These are compiler runtime libraries to handle supporting native C/C++ operations that are not implemented in hardware. For example, should you do a 64-bit division operation on an architecture that doesn't have such an instruction, the compiler generates a call to a library function implemented in these libraries.
* -lc -- This is the C runtime library. Here you may find the implementation of printf, for example.
* -lgcc, -lgcc_s (again!) -- The C runtime library's implementation may need to call out to these compiler-generated function calls, so include the libraries again in the search path because legacy linker order means you have to.
* /usr/lib/gcc/x86_64-linux-gnu/9/crtend.o -- This is the counterpart to crtbegin.o. Whereas crtbegin.o includes some stuff that will happen before all the user code is included, this includes some stuff that will happen afterwards.
* /usr/lib/x86_64-linux-gnu/crtn.o -- Ditto, but for crti.o instead.
On a modern glibc system, the linker will arrange for the entry point to be included in _start, defined in crt1.o. The Linux ABI formally specifies how the register state and stack will be arranged when you load a program image, and _start will translate this ABI into a function call invocation to __libc_start_main. __libc_start_main is implemented in libc.so, and will handle calling global initializers and the like before calling the main function implemented in your program.
In practice, most modern executables are dynamic executables, which means that executing your program means the Linux kernel actually executes another program instead (/lib64/ld-linux-x86-64.so.2 for x86-64), which will take on the burden of loading your program and then calling _start itself. This is to support loading shared libraries (such as the C library!) and implementing relocations, which the Linux kernel does not know how to do.
All of this tends to fall under the purview of linking and loading, which is generally not handled by compiler writers. Even most new programming languages tend to find it easier to link their programs using your platform's C compiler because it's nasty to worry about all of these details yourself.
Yes true. Check 5.1.2.2.1 and 5.1.2.2.3 in the standard.
If you don't treat 'main' specially you won't have a conforming C compiler. It's unique in accepting different signatures, and for its return value syntax and semantics.
You cannot just compile it as a normal function and link it with a runtime routine. You need compiler support for it.
Good point. That makes it relatively difficult (not impossible) to compile `main` differently from other functions, other than diagnosing bad signatures if that's what the hosted environment requires, since it has to be callable like other functions.
There are probably implementations that require compiler support, but it is not required by the standard and not true of many common implementations. Support is by the caller, as described in others' parallel comments.
> You cannot just compile it as a normal function and link it with a runtime routine.
You can. As a concrete example, for the following two programs,
int maim(int argc, char *argv[]) { return 0; }
int main(int argc, char *argv[]) { return 0; }
the assembly code produced by gcc 9.3 x64 is identical except for the spelling of the identifier. int maim(int argc, char *argv[]) { }
int main(int argc, char *argv[]) { }
They compile to different code. Can you figure out why?A function called main is treated differently in this regard to other functions, which is enforced by the standard, and so has to be implemented by the compiler.
Note that on macOS there is an additional fourth argument to main, char *apple[] (I would write this as a double pointer, but Hacker News would eat it if I did). It contains things passed on from the kernel mostly on relevant to libc and dyld.