The article says `lea` helps calculate the array relative address on AMD64. Why does the article say the problem would be tricky on 32-bit? `lea` is an old instruction. Thanks.
Main is usually a function. So then when is it not? (2015)
11–20 of 59 posts
Re: Main is usually a function. So then when is it not? (2015)
#12is a valid C program but main is not a function here.
Re: Main is usually a function. So then when is it not? (2015)
#13Complete final program for the laziest of us (after incorporating @10000truths's advice): const int main[] __attribute__ ((section(".text"))) = { -443987883, 440, 113408, -1922629632, 4149, 899584, 84869120, 15544, 266023168, 1818576901, 1461743468, 1684828783, -1017312735 }; Compilation (gcc 13): $ gcc -Wall main.c -o main main.c:1:11: warning: ‘main’ is usually a function [-Wmain] 1 | const int main[] __attribute__…
Although I found that gcc seems to be configured with -pie per default, so this compilation works:
$ gcc -Wall -fno-PIE -no-pie main.c -o main
mainf.c:1:11: warning: ‘main’ is usually a function [-Wmain]
1 | const int main[] __attribute__((section(".text"))) = {
| ^~~~
/tmp/ccq0adwj.s: Assembler messages:
/tmp/ccq0adwj.s:4: Warning: ignoring changed section attributes for .textRe: Main is usually a function. So then when is it not? (2015)
#14This won't work anymore, as compilers will now place const arrays in the .rodata section, which is non-executable. Luckily, there's an easy fix - just qualify the declaration of the array with: __attribute__((section(".text"))
I bet there are some people who wouldn't even think about the fungible nature of data types (especially if they come from a "modern" language).
Re: Main is usually a function. So then when is it not? (2015)
#15Re: Main is usually a function. So then when is it not? (2015)
#16Re: Main is usually a function. So then when is it not? (2015)
#17Back when compiler warnings possibly cost extra processing time to generate, it was possible to make gcc compile the craziest things. After much experimentation, it turned out that the smallest program that would compile and run was only 5 bytes long: main;
I still get a segmentation fault out of that when I run it. I think there's flags you can use to get the linker to not complain about missing main if you give gcc an empty file. The craziest thing I got gcc (the AVR version, specifically) to compile for real purposes was a preprocessor macro that spit out tens of thousands of asm blocks with memory barriers and nop (do nothing) instructions with "PORTB = 1;" in the m…
Re: Main is usually a function. So then when is it not? (2015)
#18This is fun. On a broader note though, entry point main-type functions have always bothered me. Maybe because I grew up as a simple script kiddie with BASIC and Bash and PHP. I like code that starts executing from the first line and then runs whatever functions it wants to run. I realize that's just an abstraction of main() but it's a pleasant one for me. There's something more constricting about there being one func…
As a compiler author, there are a bunch of nasty surprises to this approach. If you execute a file line-by-line, then functions only exist once you "reach" them.
If you write:
def a(): b()
a()
def b(): ...
...then a() needs to crash when first called, because b() hasn't been declared yet. So your functions need to be invoked via some kind of table, and can't easily use jumps to hard-coded offsets. And b() can't be inlined.There are dozens of these problems that come up when generating efficient code. And the easiest way to fix them all is to make your entire program "exist" from the beginning, so it can be compiled and optimized as a whole. Which is how you wind up with main().
Re: Main is usually a function. So then when is it not? (2015)
#19This is fun. On a broader note though, entry point main-type functions have always bothered me. Maybe because I grew up as a simple script kiddie with BASIC and Bash and PHP. I like code that starts executing from the first line and then runs whatever functions it wants to run. I realize that's just an abstraction of main() but it's a pleasant one for me. There's something more constricting about there being one func…
> There's something more constricting about there being one function to bootstrap everything than there is about one file. As a compiler author, there are a bunch of nasty surprises to this approach. If you execute a file line-by-line, then functions only exist once you "reach" them. If you write: def a(): b() a() def b(): ... ...then a() needs to crash when first called, because b() hasn't been declared yet. So your…
Line-based stuff like BASIC's GOTO/GOSUB was kind of a fun workaround to the idea of even having functions at all, and I'd happily live in that place still... but... as somoene who manifestly does not write compilers, is it still an extravagant demand in this day and age to ask a compiler to check and include/throw for all the functions out-of-order before running a code file from the top?
[edit] What I mean is, this was fundamental to ES3/4 bytecode compilers for VMs like Java or Flash, and it would be absurd to ask e.g. Javascript coders [edit: said Python, don't work with Python, there are cases in PHP where it's necessary] to order their functions in the order they're invoked with virtuals to place them. This is like providing toilets on a cruise ship. It's barely even a "service", like whereas garbage collection or something is an actual service. Restructuring the order of function definitions as you build out dependencies has got to be one of the worst wastes of coder time I can think of. Great if you really can find an optimization by doing that, but the way people code these days that basically never happens. We have to assume that everything we write gets compiled anyway, or why else is it in the code! If there are no dead branches, what's the purpose of not "existing"/let's say pre-virtualizing all the branches, regardless of which order they're written in? (Serious question).
Re: Main is usually a function. So then when is it not? (2015)
#20This is fun. On a broader note though, entry point main-type functions have always bothered me. Maybe because I grew up as a simple script kiddie with BASIC and Bash and PHP. I like code that starts executing from the first line and then runs whatever functions it wants to run. I realize that's just an abstraction of main() but it's a pleasant one for me. There's something more constricting about there being one func…
As someone who basically started coding with C I feel the other way around, unsurprisingly. Even in scripting languages when I write something non trivial I tend to encapsulate everything in functions and then have a `main()` call at the bottom of the file. I think it's one of the things python got right with the `if __name__ == "__main__":` idiom that lets you import any script in a REPL to test individual methods for instance.
(Although the actual syntax of `if __name__ == "__main__":` is IMO utter trash and it amuses me that a language so obsessed with getting rid of symbols and looking like pseudocode decided that such cumbersome, obtuse and ugly looking boilerplate was just fine.)