And kudos to you for following up with your own exploration. It's so often the case that the most interesting stuff is hidden in what other people are wrong about.
HN user
breadbox
My personal website is at muppetlabs.com under my username.
Not as much fun that way.
A valid point! Clearly the correct solution would be for the kernel module to check if the filename contains the substring "32", and if so it should load it as a 32-bit binary.
So I read the other article, and I saw that bit that disagreed with my essay. My first thought was, "Oh, of course that's how it works. How did I get that so wrong?" My only excuse was that this essay was originally a tech talk and I was under a deadline. (But I really should have caught it when I wrote it up as an essay.)
So I was going to go edit my essay, when I learned that my essay was also posted on Hacker News. And now I discover that someone has already called out my error before I could fix it. Sigh.
Anyway, I just thought I should acknowledge this before I go to fix it.
I couldn't help myself. Despite my better judgement, I wrote an extension to my original essay specifically dissecting this response. (It's now linked at the bottom of the original page.)
Thanks for sharing this transcript with me.
And thank _you_ for your thoughtful response!
I don't think that's a fair characterization of the statement. It's the type of mistakes, not the bare fact of them, that suggests a lack of what we could call "understanding".
Hey, if we can distract Chat-GPT with becoming an expert INTERCAL programmer, then I say "Win-win!"
If I complain about an answer given to me by one librarian, I'm complaining about that answer and that librarian. If you can find a more knowledgeable librarian somewhere else, that doesn't affect my complaint.
But to be clear, there are no screenshots in the essay. I assimilated the HTML directly into the document.
Look, I understand your point. I really do. But I feel that (perhaps due to one or more of your acknowledged biases) you're applying the wrong context to the situation at hand.
Namely: this is INTERCAL. There is no freaking standard. The "standard" is a 60-page text file written in 1973. The current compiler was written 90% based on this joke-filled document, and 9% new ideas because ESR came up with something even more ridiculous. (The remaining 1% was Don Woods responding to emailed questions by consulting his memory. He still has paper copies of the SPITBOL source code, but the original compiler hasn't been run in over 50 years.) There is no standard because at any given time there are at most three people on the planet who care one iota about INTERCAL standardization, and are only willing to put in any effort if it would be funny. So, for example, the question of what sort of randomness the double-oh-seven operator is contractually required to use is simply not a contextually relevant question.
You seem to be suggesting that it might be possible, even thinly so, that Chat-GPT somehow misapplied a strict standard of randomness in the formation of its response, instead of simply papering over a hole in its knowledge with a bit of improvised plausible-sounding guesswork, a well-documented behavior of both Chat-GPT and thinking entities worldwide. If not, then I humbly apologize for misunderstanding your point. Otherwise, I must politely agree to disagree.
And I'm sorry that my essay rubbed you the wrong way. Perhaps one day you will find it better than you do now, but if not then I hope it passes from your memory quickly.
And again, a heady mix of accurate observations with complete bullshit. Separating out the misinformation is, as always, left as an exercise for the reader.
Unless `write()` returns an error, in which case rax will contain a negative value. I've had to ditch that shortcut many times because of this.
Nice to see another approach to this subject! Kudos to the author.
I have a couple of responses to specific points brought up in the article.
The author suggests that the original 45-byte executable no longer works on modern systems. If so, this is news to me. Admittedly my current machine is a bit behind the cutting edge (4.15), but what's there should still work. If people are finding the current version to fail for them, I'd appreciate some details on their setup.
* I respectfully disagree that 32-bit executables are "less relevant" today; I suspect they will continue to be supported for many, many years to come. Of course for a new explorer 64-bit executables are far more interesting, but when you're shaving bytes at a time, you can't beat a 32-bit executable.
* Many people are unaware that my original essay is only the first of a series that I wrote. (All of the essays are linked at the bottom of the original.) I note that my smallest 64-bit ELF executable without introducing invalid fields is also 120 bytes, so that's cool.
* However, by taking advantage of unvalidated fields, I was able to produce a working 64-bit ELF executable that is 84 bytes in size. The overlapping is a bit tricky, but I've verified that it continues to work on my box. See http://www.muppetlabs.com/~breadbox/software/tiny/return42.h... -- all variations of my return-42 executables are collected there.
* My smallest 64-bit ELF executable that prints "hello, world\n" (no punctuation: I always use the string from K&R) is 98 bytes. I don't have the assembly for that one posted on my site, but it uses the same layout as the 86-byte executable.
You might be interested in the sequel essay, which covers dynamic linking under ELF: http://www.muppetlabs.com/~breadbox/software/tiny/somewhat.h...
I find I need to quote myself from 2013, as I can't really add anything further to it:
Wow. I honestly wasn't expecting to ever see this on the front page of HN again, given the current ubiquity of 64-bit Linux. (And yes, before anyone asks, I've played around with minimizing 64-bit executables. Unfortunately they are both larger and less forgiving of tomfoolery. The smallest 64-bit ELF I've created is 84 bytes.)
Since it is here, though, I want to take the opportunity to say thanks to everyone who's expressed their appreciation of my essay. And I should note here that writing that essay, so many years ago now, is one of the better thing I've done for my career. Share what you have to learn the hard way; the effort won't be wasted.
And indeed, size optimization is actually the least practical subject to learn from that essay.
Is the author stating that _start is an interface to the OS then? It's interesting I never thought of this as being an interface.
Perhaps it's not the best term, but it's not really incorrect. I probably wouldn't phrase it that way today (20 years later).
Is this just a long-winded way of saying _start sets up the stack for the new process? WIthout a stack you can't "set up" argc, argv etc.
Well -- to be precise, the stack is created by the kernel during the exec system call. The kernel also copies the argument and environment strings into the process's memory. However, the kernel does not create the argv array of pointers, or the envp array. Building those arrays is the job of _start(), and that is what I meant by "setting up argc and argv".
Please note: That was the case back in 1999. Things are different now -- I think it changed with the 64-bit kernel? In any case, nowadays the ELF loader in the kernel also builds the arrays.
I would also be curious what "among other things" might include.
As before, it depends on the C runtime. The _start() function might ensure proper initialization of libc, for example. (Again, with current binaries that's usually done via an `.init` section, but in 1999 that was not the norm.)
(Note: I'm assuming from the reference to "map layout" that this comment is directed at the original article, and not the video mentioned in the parent comment.)
Reading the assembly language is what many (perhaps most?) people would do at that point. But not everyone is as comfortable with reading assembly, and I wanted to show that a lot can be done without taking that step.
Also, "easier" is a relative term. It was far, far easier for me to examine the data files sitting comfortably in front of my Linux box, than to try to pull together a decent debugging setup inside of a dosbox before making any headway. There's always more than one way to do it.
I'm afraid that's something I don't have any experience with. However, another commenter mentioned a cool video he did on just this subject, at https://news.ycombinator.com/item?id=21728298 -- so maybe check that out?
Thanks for the kind feedback. Unfortunately I don't know much about communities. Most people who do reverse engineering focus on examining code/assembly, but my limited experience is solely with data files.
Thank you for the compliment, but I hope my essay convinces you that it's actually not as hard as it sounds!
Yes, part of the usual process of making a tiny binary is jettisoning much of the overhead that debuggers depend on in order to find their way through an external program. Not just the debugging symbols themselves, but things like section header tables and maintenance of linked stack frames in the running code. Dumping all of that saves space, at the expense of making the resulting binary more and more opaque.
Fascinating! Thanks so much to the company for writing this followup -- every year or so I've wondered how this company was doing and if the experiment was still going. It's heartening to learn that it is.
I typically end up playing card games -- either various forms of solitaire, or something like Hearts with AI opponents.
I found Kopp's article easier to follow after reading Siegel's, myself. YMMV
Of course it's a bummer. Reading about sexual abusers getting away with same is always a bummer. But remember that this heads-in-the-sand attitude of I'd-rather-not-find-out is how these people get away with it in the first place. It's how Catholic priests continue to prey upon their own communities.
In short, don't shoot the messenger.
Me, I'd put it on my resume.
And therein lies the issue. Everyone does just that, causing needless clashes. If you're writing a library, you can either switch back to the standard type names in your external header file, or you include the typedefs/macros there as well. The former choice ruins some of the point of having these types, and might even mask cross-platform issues. The latter runs the risk of clashing with the user's owns typedefs, or with another library writer's typedefs. (And god help you if exactly one library writer chose to do it via macros.)
While the article is strongly sympathetic to Padgett's answer, various hints seep through that Padgett is actually a bit of a crackpot, and his solution is a bit of a Bible Code. Nothing too obvious, but the sort of thing one recognizes from reading about other crankery. And then, two-thirds of way into the article:
Most Elgar scholars I contacted said they have stopped responding to Padgett’s persistent inquiries.
Sigh. This sentence should have been in the lede.
Interesting, but isn't this kind of the opposite of "do it live"? I would think "lip synch" would be a better name for it.
I've done a couple of live presentations in my career (in fact I just did one last Friday). I think they're great for audiences, when the circumstances permit. People connect to the physicality of the typing in a way that looking at some screenshots just doesn't provide.