Simpler "Hello World" Demonstrated In C
An anonymous reader writes "Wondering where all that bloat comes from, causing even the classic 'Hello world' to weigh in at 11 KB? An MIT programmer decided to make a Linux C program so simple, she could explain every byte of the assembly. She found that gcc was including libc even when you don't ask for it. The blog shows how to compile a much simpler 'Hello world,' using no libraries at all. This takes me back to the days of programming bare-metal on DOS!"
*sigh*
Been there done that... on the PDP-11 in 1979.
FYI, Steve Jobs came up with the idea for the "Hello World" app.
Interesting, but she does sort of sidestep the whole 'Hello World!' part of a hello world program.
Adding a static 11k or so is insignificant for any program which actually does anything useful.
http://web.archive.org/web/19991128041233/http://muppetlabs.com/~breadbox/software/tiny/teensy.html
November 1999. Slow news day much?
This post expresses my opinion, not that of my employer. And yes, IAAL.
Maybe it wasn't her fault, but the /. summary promised our little greeting. I expected a trip down memory lane to the old "DOS" interrupt INT 21H. But not even.
FAIL
Ok, this is wicked great in theory. Our programs have become bloated. We do have them taking up too much RAM, HD space, and CPU time. But after reading through this in-depth analysis I have to wonder if it's all worth it.
If we're willing to leave behind all pretenses of portability, we can make our program exit without having to link with anything else. First, though, we need to know how to make a system call under Linux.
Or I can just write it the old way, making the file size larger and not have to concern myself with portability and how to make system calls under Linux. After all that's what the whole point of this all was right?
Start with: 10 PRINT "Hello World" 20 END The Went to: 10 PRI "Hello World" Then finally came down to: 10?"Hello World"
45 bytes, huh? I can do it in....
#!/bin/sh
exit 42
18 bytes and it's portable across all Unices. Maybe the assembler version is faster, though?
Nice to see someone actually caring about removing bloat from software after VB, Java, .NET and the
corporate culture behind them literally destroyed any incentive in producing optimized code, nearly
killing the demand for skilled programmers capable of writing such code.
Also, for those working with smaller systems this is a godsend.
Since when does a Hello World program not actually output anything?
I think you missed the point of the article.
The author is trying to highlight that amount of bloat in modern programs is so rampant that even "Hello World" is excessively over sized for what it accomplishes. How can we as programmers expect fast, efficient, lightweight code when our compiler (even ones as popular as gcc) are bloating the program without being asked to?
Why doesn't it fit in TFS?
If God forks the Universe every time you roll a die, he'd better have a damned good memory.
As to the point of this... we recently had a story about how computers had gotten "too big to understand".
And here we have a program, 45 bytes long, for which every single byte has a well-explained purpose. It's getting back to the bare metal and that's what makes it interesting. =)
Awhile back I read another similar article. In the article the smallest PE created is a bit larger (97 bytes), but a little more standards compliant. More interestingly, however, the author crafts a program that downloads and executes another program in only 133 bytes.
Hikery.net - The best hiking site ever. Made by yours truly.
Mainframers have been using this most simple of all utilities for decades - literally. The Wikipedia entry on it has a good write-up about this (literal) do-nothing program. It's whole purpose is to provide a mechanisim to to exploit the various functions contained in JCL to create, delete, and otherwise manipulate datasets on mainframes.
The wikipedia entry is here: http://en.wikipedia.org/wiki/IEFBR14
Ken
Really though, I've never understood the need to use gender terms when its irrelevant.
One of the earliest machines I learned programming on only had 256 bytes of memory.
(Yes, that's right, 256 B Y T E S of memory.... one quarter k of ram... less than your digital wristwatch probably has... )
The point is the program has bloat that can be eliminated.
You might not have to worry about it, but then again...
Besides, keeping the knowledge of creating bare metal code is important and still very useful for a number of devices or situations, just not with most your PC desktop apps.
Ah the old days, when I was young enough and bored enough to write relative addressed machine code for fun. (Couldn't afford the damned assembler back then.)
At the end, the code was assembler, and the compiler wasn't even called - just the linker. I can't say for sure where a C program ends and an assembler program begins, but I'm fairly certain that the last few iterations are assembler, based on the "let's do away with the compiler" suggestion.
Also, "Hello World" programs have to, you know, actually display the message "Hello World" - this is a program that isn't written in C, and doesn't write "Hello World" - care to revisit the title of this entry?
Ken
I had a laptop that was really short on memory back in 1996 or so. I liked having the six virtual consoles, but rarely used them, so I wrote a program that would wait for you to press enter, then exec the regular login program. It copied the executable onto the same page as the stack and had no globals, so at run time, it used exactly one page of RAM. I used the same technique as the author here of calling syscalls directly instead of using libc.
Which will dynamic link glibc even when you need static. (Think it's nsswitch???)
I understand the point of the article, and everything else mentioned here. I just think that the amount of time spent eliminating 11k from a program in this case is irrelevant because any real application is going to need libc. It's not like she needed to strip it out so it would fit inside a tiny corner of an embedded processor - she's probably running it on a PC with anywhere from 1GB - 4GB of RAM.
Back in 1970 I was programming in assembler on the CDC mainframes (3200 & 3300) in the Compass assembler language. Also it was not unusual to drop into machine code and code directly from the console and then save your program in machine code either to the printer or to the disk driver.
Now that was hands on... and I still miss it... sigh.
Also I programmed in Fortran and COBOL as higher languages.... but nothing like the power of assembler.
And in the end, the love you take is equal to the love you make
When I got my first C compiler...in 1981
Thank God we have finally crossed this hurdle. The baffling complexity of helloworld.c is no longer an obstacle to world domination.
I think we can now finally say once and for all that 2010 will be the year of Linux on the desktop.
The whole point was learning ELF structure and why things were they way they were. Didn't you ever wonder why a "hello world" program took over 4000 bytes on a modern computer, when in 1980 a Commodore VIC-20 managed to play games in less than 4K of available memory? This wasn't a waste of time.
With the Hello World program rewritten, scores of publishers will be updating their programming books and charging more $$$ for their new door stoppers.
OK, when I first read this, I thought to myself, "now why in the hell would anyone care to do this?"
Then it dawned on me. One stoned programmer said to another....Yeah, that's probably how it went down. Both now, and back in 1979, when you could still smoke in the Data Center...
Just because her machine has that much RAM available doesn't mean the program has to use it.
Good, inexpensive web hosting
"Simpler" 'Hello World'?
SIMPLER? Perhaps in the sense of using less bytes, but the article is well beyond your average first year comp sci student so it's certainly not simpler in the sense of being understandable.
This is what I call "Occam's Wedge", what's simple to you and simple to me may be entirely different leading to a wedge in our argument with both sides insisting Occam is on their side.
Cwm, fjord-bank glyphs vext quiz
But my stupid build process that generates the bloated Hello World is much more maintainable. Now get off my lawn.
Colorless green Cthulhu waits dreaming furiously.
Waiting for someone to crack this new hello world code and post it on bittorrent. Any links appreciated.
Seth
$5 / month hosted VPS on linux = awesome!
"An 11k app is not going to make me, or my computer, say 'Good Bye World'"
It is if your computer is a 38-cent Atmel AVR tiny 10, which only has enough space for 512 12-bit instruction words. This chip is about half the size of a sunflower seed, but is faster, and, in several ways, more powerful, than the original $5000 IBM PC from 1981.
Get away from the idea of Gigahertz desktops and $1000 laptops and join the real computer revolution!
For me, if it costs more that $5, it's not a computer that I take seriously. It's just a 20th-century digital processing appliance.
Shouldn't the linker remove unreferenced functions?
I've had this problem with gcc for a while, with C++ code. I was writing some embedded code, and I wanted to use some simple C++. Just by adding a #include of one of the stream libraries. the executable grew by 200k, even though none of it was referenced. The C++ code in iostream is template-generated anyway, so even if the compiler wanted to include the code, it can't until I instantiate it.
There's been an awful lot of discussion about what is or isn't simple,
and people have gotten a pretty sophisticated notion of simplicity, but
I'm not sure it has helped.
-- Ward Cunningham
Colorless green Cthulhu waits dreaming furiously.
Not to mention the submitter didn't read the article. It isn't Hello World, and it isn't in C (at least not by the end of the article).
scripts. :)
After all, there's no strict requirement that executable files on Linux be native machine code.
File under 'M' for 'Manic ranting'
because any real application is going to need libc.
Real programs do not need the entire libc imported, either.
It used to be easy to import minimal sets of dependencies, and in fact it used to be default behavior. Libraries were designed in a modular fashion so that a program that only needed the module that contained getc() didnt also pull in the module with atoi(). These days, pulling in any module from a library likely brings in every module, and its a sad sad thing that compilers, linkers, and libraries have strayed so so far from the minimalist-by-default days.
The modern ways are bloat. Defaulting to maximal rather than minimal. I don't care that the target system has 16 gigs of ram, and its programmers who shrug it off because they have so much ram (such as you) that are the problem.
"His name was James Damore."
...in 45 bytes - Impressive!
This is because we are no longer linking the binaries statically (one object file for each function), but are using dynamically linked libraries. And your libc is't loaded only for your program. The same spot in ram is shared between all programs that are using it making the total ram spent for each program rather small, probably even smaller than if you would statically link the object files of the functions you need.
Patch the strip utility on Linux, send in the patch and see if it gets accepted. Then let's see a follow-up of that on Slashdot. She's taking a lot of flack here; but there's value in the work. It just needs to be applied in a more practical way.
For all intensive purposes, "whom" is no longer a word. That begs the question, "who cares"?
... and pile up on 64x8 TTL Proms!
Yeah, but the 45-byte program doesn't say "Hello World". In fact, there's no example that I can find in TFA that outputs that message or any other. So the summary is incorrect on its face. TFA doesn't show a simpler "Hello World" program; it doesn't show any sort of "Hello World" program at all.
I feel cheated, and tricked into reading an article that didn't do what was advertised.
(It's not the author's fault, of course; the author didn't claim to be writing the sort of program that the summary talked about. Though I was a bit disappointed that only the first few examples were in C. The article was almost entirely about assembly-language programs. So again, I was a bit disappointed, since I was hoping to learn something about making C programs smaller. This was done only in the first example, and it was made smaller by removing its call on write() so it didn't output anything at all. I already understood that I can make programs smaller by removing all functionality. ;-)
Those who do study history are doomed to stand helplessly by while everyone else repeats it.
otherwise she would have done something like this:
#include
void main(void) {
while (1) {
malloc(sizeof(unsigned long long));
}
}
slashdot filtered my stdlib.h, but that should be obvious to everyone here over the age of 20, I think.
You really do have the wrong sized glass.
An 11K program is stored on 22 512 byte blocks. Reducing the block count by 1/22nd reduces the amount of I/O required to load and execute the program by 95%. By reducing the overhead of this example even further to the absolute minimum, you can increase considerably the remaining space which can be used for important code in one block I/O. Byte counts in Ethernet frames are equally important. To give an idea of how significant this is, the Slammer Worm was 376 bytes. For an application that nearly shut down the Internet that's a pretty good example of the possible leverage of code density.
Reducing code size is a critical factor in achieving optimal efficiencies real-world businesses use to compete against each other. It's not the only critical factor, but it is one critical factor. It's important.
Help stamp out iliturcy.
Wow. When I got bored with having to write it for the 12th damn time, all I did was this:
if the answer isn't violence, neither is your silence / freedom of expression doesn't make it alright
I wasted too much time reading this one... nothing surprising about what I found in it. Step one, don't write it in C. Step two, stop linking to things that aren't needed. Step three, perform the functions contained in the library omitted manually. Step five, start cheating in the elf binary format.
The only thing interesting about it was that the article pointed out an interesting fact -- Linux will run inappropriately formatted binaries. BAD. Linux kernel people? Are you reading this? Fix it before someone figures out how to use this in making and executing more exploits.
It's just a 20th-century digital processing appliance.
Mine is a 21st-century appliance, thank you very much!
Back in the DOS days, any moderately competent programmer knew how to copy arbitrary data to screen buffer, allowing you to display text without any libraries. It's been many years, so I am probably getting this wrong, but in psuedocode it'd look something like
char*cp="Hello World";
char *addr=0xB8000000;
while(*addr++ = *cp++);
That's the C version, of course. You'd actually do it in assembly. My suspicion is that you could do it in on the order of 20 to 25 bytes, but again, it's been decades since I've done anything like that.
The cake is a pie
"At the end, the code was assembler"
But, the key point is that the user didn't generate that assembly. The user wrote a C program (granted, the program doesn't actually do any output - it just stores a string in memory, then exits). The user called the compiler to compile the program. The user then *disassembled* the object code which was created by *the compiler*. So, the assembly you see was generated (indirectly, via the objdump command), by the C compiler.
Exception: the user did create a small assembly file with the place-holder _start function. Perhaps, this example would have benefitted by the user defining the _start() function in C also, and using the compiler to compile that - not sure if that actually would have worked or not, but would have been interesting if she had tried.
One other point I'd like to make - ultimately, every C program has to have some assembly *somewhere*. When you call the printf(), printf itself either must use some assembly to interact with the operating system (in order to cause output to be sent to stdout), or printf *might* punt that off to another function, which then has some assembly inside it. The only reason you can do *any* input or output in C (or any other language for that matter) is that, at some point, somewhere, either in the compiler itself, or in a standard library, someone has provided the necessary assembly code for you.
In the case of C, the language designers decided to make the C-language pure 'logic', without any notion of input or output statements, or operating system interactioni, and do all input/output/system calls via library functions (whether you use the standard library, or a 'third-party' library [ I use the term third-party loosely here, because the 'third-party' lib might actually be provided by your compiler vendor, but it's just not the standard library]).
The fact that helloworld.c compiles to 11k has less to do with bloat than it has to do with people generally not caring about 11k. You could get rid of that 11k, but to do so, you'd have to make trade offs that either make real programs either slower or bigger, or make compilation slower. Very few people would make those trade offs in the other direction. Those that do either use special purpose compilers or (more likely) write in assembly.
The cake is a pie
Sure it's been done before. But this time it was done... by a woman!
/.
I'm not saying that's actually significant, but it seems good enuf for
Case in point: http://hardware.slashdot.org/story/10/03/15/0028201/Mario-Reduced-To-8x8-With-Open-Source-and-Arduino
You're right! I'm going to throw my laptop out the windows right now! Reading slashdot will be so much more fun on a computer smaller than a sunflower seed.
"A week in the lab saves an hour in the library"
But, but... the ATmega644P costs 9.28$USD!
And you can keep your half-sunflower seed ATtiny10, I'd rather use a DIP-8 ATtiny85!
And your ATtiny10 is actually 1.19$USD, so don't crap on my 2.44$USD ATtiny85. ;)
* This message was not approved nor endorsed by Digi-Key.
These days, costs of development and deployment, not runtime memory usage, are the limiting factors in software development.
http://outcampaign.org/
Guy reminds me of an old joke.
What's the difference between a bitch and a whore?
A whore fucks everyone. A bitch fucks everyone but you.
I agree that simplicity of code is the underlying factor here but coming from someone who's been coding in assembly for the last four hours (Shoot me, please!) I honestly don't understand why the libc library was included when not called for.
I'm far from an expert on the intricate workings for C but I'm under the assumption that making a check if the library is required or not is fairly simple.
If you're actually programming on "bare metal", you're not really using DOS, are you? After all, DOS is an operating system -- a layer between your code and the hardware.
You could get rid of that 11k, but to do so, you'd have to make trade offs that either make real programs either slower or bigger, or make compilation slower.
I guess that's a matter of perspective. It's been nearly 20 years since I did this the first time, but off the top of my head and using nothing but debug.exe, I just produced a complete, working hello.com file in about 27 seconds. How many modern C IDEs would even have started up with a blank file in that time? (In case anyone's curious, it was 19 bytes long, which I suspect you can't beat on a Windows box without playing with video memory directly.)
I wonder how often we add "just another 11k" to our programs today by extending your argument, and how many of them could be avoided similarly easily. Given that it takes probably a minute for a basic OS and GUI to start up and reach a useful state on a contemporary high-end PC, I'm betting it's a hell of a lot more than necessary. All that flexibility has a price, to be sure, but I suspect at least part of the problem is that we just haven't got very good at building large software systems yet, either technically, or in terms of tools, or in terms of management.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Oops! Poster misplaced the quotes. Subject should read:
"Simpler" Hello World Demonstrated In C
Oops.
Here, I found your <stdlib.h> for you. < ftw.
Cheers, Chris
One of the earliest processors I used had only 256 bits of RAM (Yes, that's right 256 B I T S of memory)
Yeah its fine that it loads the whole dynamic library when I am dynamic linking, it is not fine that it imports every module in the library when I am static linking.
Dynamic linking has its own pitfalls (library must be there in a common location, or all is for naught)
"His name was James Damore."
If I were her teacher I would triple her home work for wasting time like this. I would also administer reciting ELF32 and ELF64 specs and always writing her own linker map file from scratch every time she had to run a C/C++ program.
#hello world tiny program
.data
.text
.equ SYSCALL, 0x80
.equ SYS_EXIT, 1
.equ SYS_WRITE, 4
.equ STDOUT, 1
.section
hello:
.ascii "hello world!\n"
.section
.globl _start
_start:
movb $SYS_WRITE, %al #put write syscall in eax
movb $STDOUT, %bl #set stream to stdout
movl $hello, %ecx #give address of start of buffer to print
movb $13, %dl #how many characters of buffer to print
int $SYSCALL
movb $SYS_EXIT, %al
int $SYSCALL
The above is a tiny hello world program i wrote myself, it's worth noting that even the resulting binary is larger than it needs to be, I wound up with a 133 byte binary by moving the text string into the ELF header via hex editor, and changing the instruction data to point to the new addresses.
Kind of hard to get it smaller than that while keeping it in ELF format, considering the actual object code in the binary was something like 15 bytes with the data illegally in the header.
"An 11k app is not going to make me, or my computer, say 'Good Bye World'"
It is if your computer is a 38-cent Atmel AVR tiny 10, which only has enough space for 512 12-bit instruction words. This chip is about half the size of a sunflower seed, but is faster, and, in several ways, more powerful, than the original $5000 IBM PC from 1981.
Get away from the idea of Gigahertz desktops and $1000 laptops and join the real computer revolution!
For me, if it costs more that $5, it's not a computer that I take seriously. It's just a 20th-century digital processing appliance.
Agreed, if I can get 100,000 part pricing on a Blackfin 533....
Actually, no, I used to use gcc against an m68k embedded target as part of my daily job writing firmware, and 11k does matter when your total program space is only about 256k.
Even today, I'd much rather compromise compile time for smaller, faster code on the output side. I live in the small embedded realm, though, and size is often directly related to speed due to the sloth-like nature of the memory bus.
It took me a weekend a few months ago to write a "Hello world+cat+string manipulation+malloc+free+argv+envp" program for amd64 that worked on Linux, OpenBSD and FreeBSD with the same exact binary and no emulation using mostly C code and about a dozen lines of assembly.
It later degraded into a posix cross-platform mini-c and objective-c 2.0 runtime library, but you can do far more amazing things than calling the exit(2) syscall in an obsolete architecture.
10 little-endian boys went out to dine, a big-endian carp ate one, and then there were -246.
You mean 50. The rest of the civilized world, those of us not eating tapioca pudding and watching Matlock between shifts of drooling on the keyboard, switched to better languages like C++ and Java
TFA explains it: main() isn't the true start of the program, _start is. That resides in ctrl.o, which fires off a bunch of setup stuff before calling __libc_start_main, which in turn kicks off main(), and off your program goes.
To put it as a car analogy: What she found is that turning the key to start doesn't just activate the starter, it also activates the airbag system, the traction control, and the radio too. And if all you want to do is start the engine to prove that it runs (ala Hello World!), then it's kind of silly to lug around all that extra "unnecessary" crap too.
Or something like that. Sadly i'm a better mechanic than a programmer (4yrs vs 1yr), but i'm working on fixing that. :)
It's a great article. But it's not new.
I referred to it as a reference in something published by developerWorks in 2005.
http://www.ibm.com/developerworks/power/library/pa-spec12/
Shouldn't "news" be, say, less than HALF A DECADE OLD? Oh, wait. It's kdawson, who has a nearly magical power for making bad decisions.
My blog: http://www.seebs.net/log/ --- My iPhone/iPad app: http://www.seebs.net/seebsfrac/
How many modern C IDEs would even have started up with a blank file in that time?
A ton of them? I just opened up Visual Studio 2008 in 3 seconds and Borland C++ Builder in 2.
Mod parent up. This is all a semantic game about where significant portions of functionality are stored (and thus counted or not). After all, back in the "pre bloatware" days, you'd have had to manage all of the complexities of machine management and I/O yourself. The assembly would have been much larger to achieve the same effect.
Yes, you can make the argument that Linux comes with screen I/O, a scheduler, memory management, etc. already, so that's just overhead, but as others have pointed out, you can say the same thing about bash. It comes everywhere and is just overhead.
STOP . AMERICA . NOW
Nice, though HOTBASIC which is as powerful in scope as C and much easier in syntax does it in:
4kb for WINDOWS. :D
It strips everything it doesn't use. Creates the smallest, fastest exe's out there.
Hello World !
***Yeah, but the 45-byte program doesn't say "Hello World".***
Yeah, noticed that myself. Looks to me like he/she got rid of printf, but never replaced it with anything.
FWIW, here's a link to an 18 byte version of "hello world" machine code version from a couple of decades ago that actually displays the text under msdos and, I assume, Windows 9 when booted to a command prompt.
I don't think we should all be stuffing bytes into memory with DEBUG. But neither do I think much of C, C++, Java which have always seemed to me like a deceptively difficult way to do simple stuff poorly. Surely there must be some middle ground that doesn't create unreliable, insecure, bloated, buggy software put together from overlapping layers of distraction. Wish I knew what it is.
I really don't think that we live in the best of all possible worlds.
You can't see ANYTHING from a car, You've got to get out of the goddamned contraption and walk...Edward Abbey
c:\ xxx>debug :001D
-a
mov dx, 100
mov cx, 000D
mov bx, 1
mov ah, 40
int 21
mov ah, 4C
int 21
-f 111 "Hello World!"
-a100
mov dx, 0111
-r cx
-n c:\ xxx\ hello.com
-w
-q
c:\ xxx>hello.com
Hello World!
c:\ xxx>dir hello.com
03/18/2011 11:29 AM 29 HELLO.COM
Try programming a micro-controller and suddenly you'll be facing hardware limits that force you to favor small unreadable code over bigger more maintainable code. There is a solution for it though... comments! Lots of them :D
DigiKey? You're gonna quote digikey pricing?
You're buying a 12-oz beer at a mini-bar in your room at the Ritz, where everyone else shops at Costco...
Doesn't matter anyways because demand paging ensures that only the parts of libc that your program actually uses will be pulled into memory, so all the extra junk will remain on disk.
There's also tiny PE: http://www.phreedom.org/solar/code/tinype/ .COM: http://board.flatassembler.net/topic.php?t=10847
and tiny
But it's possible he could make it shorter. Linux has used ELF since 1.2, but it used the a.out format before that (yes, gcc still creates a file called a.out by default, but the reasons for that are historical -- the name of the output file and the format really are unrelated.) And it looks like modern kernels still have the code for CONFIG_HAVE_AOUT even if it doesn't seem to really be enabled often anymore.
In any event, a.out is a good deal simpler than elf. I'll bet he could make his program even shorter by using it.
The same spot in ram is shared between all programs that are using it making the total ram spent for each program rather small, probably even smaller than if you would statically link the object files of the functions you need.
Given the number of functions in a library like libc and the number of programs likely to need each of them at any given time, that is probably the least convincing argument ever made for using dynamic libraries.
On top of that, many applications wind up depending on subtly different versions of dynamic libraries, effectively reloading the same one multiple times and negating the space advantage. The alternative, as we learned the hard way, is DLL Hell.
Moreover, other than for near-universal functionality like libc or your basic OS integration stuff, how many libraries are really used by several different programs at the same time anyway?
Then you get to dependencies between libraries, where one "simple" library winds up pulling in half the files on your hard disk, even though nothing you're actually going to call in the main library needs any of the other stuff.
Next up, we have performance, or rather lack of it, since you can't globally optimise over code linked to a standard library the way you can to code linked statically.
Bottom line: dynamic libraries are, in nearly all cases, just a horrible mistake that history has yet to correct.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
gcc for an AVR target doesn't make an 11k hello world, though.
Probably because that's an application where it matters, and a modern PC it doesn't matter at all.
Sent from my PDP-11
There are three links in the article summary. The first is to the Wikipedia entry for "Hello World"; the second is to an article about writing "Hello World" without libc; the third is to part II of the second, an examination of the ELF format and demonstrates the 45 byte program. The summary headline is rubbish. Whoever wrote it either (a); never read either article, or (b); deliberately sensationalized it by conflating the salient features of both articles, in which case they should be working for the tabloids.
I always enjoyed the GNU Hello World packages in C and C++. They seem too large for their purpose, but I supposed they were trying to test something under the surface.
Kriston
I'm sorry, perhaps I should have explicitly included the time to create all the solution/workspace/project/perspective/whatever junk that modern IDEs use in my definition of "started up with a blank file".
In any case, the point I was refuting was the claim that to get rid of the 11k, you'd have to "make real programs either slower or bigger, or make compilation slower". I contend that in no modern C IDE can you create and build a working "Hello, world!" program that is superior in any of those respects to my insta-.com version.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Hahaha, wtf? That was actually an apt car analogy.
Now, get off my lawn!
How can we as programmers expect fast, efficient, lightweight code when our compiler (even ones as popular as gcc) are bloating the program without being asked to?
For the sake of comparison to modern compilers, I just compiled hello.c with Borland Turbo C 2.01 for DOS (copyright 1987/1988) and got this:
wc -c hello.exe
5676 hello.exe
Removing the printf and simply assigning the text to a pointer (as she did in her "second try") got me this:
wc -c hello.exe
4332 hello.exe
Changing to the "tiny" memory model from the default "small" got me this:
wc -c hello.exe
4396 hello.exe.
Looks like ELF defaults to using roughly twice as much ram as MZ did(does) in DOS. On the other hand, ELF may be doing more setup stuff than MZ -- I don't know enough about the nuts and bolts of that to be sure. I do know that the MZ header is pretty simple...
If you're a zombie and you know it, bite your friend!
I remember this from years back. Do the editors not have a sense of history?
http://linux.slashdot.org/article.pl?sid=02/10/19/1233250
If opportunity came disguised as temptation, one knock would be enough.
3^2 * 67^1 * 977^1
Back in the early 1980s, I was doing development on MS-DOS 2.11 - the first real working version of MS-DOS that resembled Xenix more than CP/M.
I was using a combination of Lattice C and assembly language to do my day job. But I was upset about the libc bloat that Lattice C would drag into the program. Over the Christmas break, I sat down and wrote a tiny version of libc, with the 60% of the calls I actually used. Most of them were either thin wrappers on top of MS-DOS Int21 calls, assembly language implementations (the string functions), or reduced functionality (printf didn't handle strange alignments, floats or doubles), and custom startup/exit code. I also structured the library so that the linker would only link in functions that were actually used. For simple executables, I saw the on-disk file size drop from 10KB-20KB down to 400-600 bytes. Another thing that reduced on-disk file size was to create .com programs, rather than .exe programs.
I was also writing the handful of unix commands that I couldn't do without (ls, cat, cut, paste, grep, fgrep, etc). Since I was implementing dozens of Unix commands, each statically linked to libc, it was very important to reduce the over-all size of each executable. Most of the smaller trivial commands were less than 1KB in size. I think the largest was 4KB. I also had an emacs clone* that was 36KB when compiled and linked against my tiny lib.
For the longest time, I carried around a bootable MS-DOS 2.11 floppy, with my dozens of Unix commands, an emacs-like editor, Lattice C compiler, tiny libc, and some core MS-DOS programs. It allowed my to have my entire development environment on a floppy that I could stick in anyone's machine and make it usable.
* We had a source license for Mince, orphaned by Mark of the Unicorn, a tiny emacs-clone that ran on CP/M, MS-DOS, and Unix. We had enhanced it significantly.
Please tag this article with "duh".
I think I'm in love.
One "Aw, Shit!" is worth 100 "Ata boys!"
Did not read TFA, but some years ago there was astory about the smallest possible ELF program, which sounded very similar or the same as the summary of TFA: a tiny program, that doesn't output anything, but doesn't need any libraries either nor does make any sxstem calls. So, it's probably a dupe!
And it's written by a Brian Raiter. Where did 'she' come from?
OOP makes people lazy and gives them less of an understanding of what's actually going on.
All that OOP code you write gets translated back into something procedural, you know.
Edward@Tomato - /home/Edward/ man woman
man: no entry for woman in the manual.
"Qua!?"
if you want c++ cstdlib would work, and that's ignoring that C is still a good language for some important fields (like kernels and bit bashing).
>debug hw.com
File not found
-a :1b
13BE:0100 mov ah, e
13BE:0102 mov bp, 110
13BE:0105 mov al, [bp]
13BE:0108 int 10
13BE:010A inc bp
13BE:010B cmp al, 64
13BE:010D jnz 105
13BE:010F ret
13BE:0110
-e110
13BE:0110 43.48 4F.65 4D.6c 53.6c 50.6f 45.20 43.57 3D.6f
13BE:0118 43.72 3A.6c 5C.64
-rcx
CX 0000
-w
Writing 0001B bytes
-q
C:\DOCUME~1\Steve
>hw
Hello World
C:\DOCUME~1\Steve
>dir hw.com
Volume in drive C has no label.
Directory of C:\DOCUME~1\Steve
03/16/2010 10:22 PM 27 HW.COM
It's funny that this always come up in conversations about bloat, because not everyone has to program for embedded code, because not everyone is programming embedded devices. It's almost like you guys are a subsubculture of programmer, to the point where many of you guys come off with the general attitude of being superior, when in fact, neither approach is superior, just different based on the situation.
/rant
One is hello world, mostly in C, the other is an example of abusing the ELF standard to create a 45-byte executable to return 42. THe submitter did RTFA, he just didn't phrase the summary well.
Get away from the idea of Gigahertz desktops and $1000 laptops and join the real computer revolution!
As a hardware engineer in the mobile industry, I agree fully. Whereas the 1990's were about powerful PC's beginning to enter every home, the 2000's were about powerful communication devices beginning to enter every pocket, the next ten years will (I hope!) be about systems of these tiny systems revolutionizing our idea of a "computer".
>> Standing on head makes smile of frown, but rest of face also upside down.
It compiles to 13340 bytes on OS X.
Hmmz, I was hoping my post was without any judgement about what is 'better' and more '133t' coding. Sorry you think otherwise :(
You thought the headline and summary described the article without calling user comments? :\
How to tell the summary contains inaccuracies: It talks about "programming bare-metal on DOS" - if DOS is relevant to your programming, then you are not targeting the bare metal any more than you are when you write a Python script.
Not only more maintainable, but filesystems should use 4k per sector, specially on raid's for performance stuff discussed on this post. This means that in a decently configured modern system, anything under 4k will still occupy 4k on disk.
- Human knowledge belongs to the world
True, but that's no excuse for a compiler/linker to bring in a library that's not needed.
Good, inexpensive web hosting
Apple defines system call APIs at the top of libc ...no static linking allowed.
This annoys people who like to link things statically, and those who want to make their own libc equivalents for things like embedded language interpreters and don't want to have to figure out vtables and dynamic linking.
But it also makes everyone else who likes binary compatibility, and Mac OS X historically getting faster with every release, extremely happy, by allowing the interface between the kernel and libc to be changed, without breaking their applications.
If you statically link, you can't do that. That's great, if your OS has pretty much no real commercial application base, and you are a technical enough person to "just recompile everything from source", but it's not so good when you are talking about an OS where commercial software is very important to customers. Customers who are either non-technical, or who are technical, but think recompiling something that was working just fine before the OS update is a complete waste of time. Lump me in with these last people: I don't believe in "bit rot", I just believe in lazy engineers not maintaining their code or defining their interfaces properly.
Yeah, if you want fast LMBench results on a null system call -- which keeps changing its definition so that it can't be gamed, exactly the same way you'd game it if you were a commercial application developer needing higher performance -- static linking seems great. But practically, most modern software is either CPU bound or I/O bound. If it's CPU bound, it spends all its time in user space, not making system calls. If it's I/O bound, it spends all its time waiting for whoever is on the other end of the network to send it more bytes. Either way, null system call performance is, frankly, unimportant to almost every possible application.
So static linking, and writing your system calls at the trap/sysenter/syscall level (with no way to change them when Intel or another chip vendor introduce a "new! optimized method of making system calls!", as has already happened twice in the past) is generally a pretty useless exercise.
-- Terry
My Atari 2600 console has 128 bytes of memory. (Yes, that's right, 128 B Y T E S of memory.... one eighth k of ram... exactly H A L F the memory of the machine the parent used to program on... )
It can be difficult to determine the size of a program when you are first starting to write it. Obviously it would be faster to hack together a trivial program like "Hello World" in a simple text editor. IDEs are more useful when you are solving non-trivial problems, like maintaining a couple hundred source files and integrating dozens of external libraries.
If that's the point of the article (which I don't think it is) then it does not make the case very well. You would need to show how that overhead scales with larger programs. Sure an extra 10k of code for Hello World is a lot, but if KDE only has 10k overhead I'd be pretty damn impressed.
We hope your rules and wisdom choke you / Now we are one in everlasting peace
I disagree, I'd say the embedded programming style is inferior. There's nothing stopping regular programmers from coding the way they do so it would be done if it had any value. The embedded guys don't write unportable assembly because it's better, they do it because they have to.
We hope your rules and wisdom choke you / Now we are one in everlasting peace
It's funny that this always come up in conversations about bloat, because not everyone has to program for embedded code, because not everyone is programming embedded devices. It's almost like you guys are a subsubculture of programmer, to the point where many of you guys come off with the general attitude of being superior, when in fact, neither approach is superior, just different based on the situation. /rant
I see it from the opposite perspective. I've never programmed for an embedded device (The closest I've come is dicking around on some code for the GP2X). Embedded, real-time, and high-performance projects might not be the general case, but they are important nonetheless.
But whenever it comes you, you get idiots like ILuvRamen above who post bullshit like "Use a real language, like $IDIOTS_PET_LANGUAGE" with the same canards that CPU speed and RAM are cheap now, etc... completely disregarding that, with each iteration, that the same attitude on the part of OS developers eats up a good part of the increased resources.
Fancy toolchains and build tools are amazingly convenient, but to never know how to work without that net in case its needed is just laziness. If you personally don't ever intend to code for a micro-controller, fine, don't learn.
/* -*- coding: utf-8-unix -*- */
#include <stdio.h>
int main(int O, char **o)
{
int l4, l0, l, I, lO[]= { 444,131131,13031,12721,17871,20202,1111,
20102,18781,666,85558,66066,2222,0 };
for(l4=0;l4<14;++l4){
for((l=l0=lO[l4])&&(l0=-7);
l>4&&(I=2-((l|l>>O)&O));l=l&O?l+(l<<O)+O:l>>I,l0+=I);{
putchar(10+l0);
}
}
return 0;
}
(founded 95,000,000 yrs ago, very space opera)
Hello (World). I am from the future. The code you have provided a link to will not run on Windows 9.
If 11k is a problem you should not compile with gcc using linux system calls. In fact, if you are programming microcontrollers you will/should have a build chain that does not include "bloat".
You're right! I'm going to throw my laptop out the windows right now! Reading slashdot will be so much more fun on a computer smaller than a sunflower seed.
Well, throwing windows out of your laptop seems more fitting to the general spirit of slashdot.
Indeed.
At 11kB each, my 1TB harddrive would only fit some 97 million programs.
Slashdot social media options: AIM, ICQ, Yahoo, Jabber and Mobile Text. Why no MySpace?
sounds like you need a new compiler/language. Aren't we, as programmers, intended to be too lazy to make compromises like that?
-- 'The' Lord and Master Bitman On High, Master Of All
are you here to kill bill (gates) to prevent windows 9 from happening ?
Yes, I'm left. You have a problem with that?
Not to mention the fact that building will be much faster (linking).
"Hello World" uses over 90% of his "iHello World" work. You would be hard pressed to make a fair use argument here. ;-)
You know, there is a difference between trolling and pointing out the flaws in your reasoning. Just saying.
So, this was written in 1999... But it's a nice read; clear and well explained.
But has anyone tested to see whether Linux still doesn't check ELF executables for nutty stuff like this? It's come a long way in the last decade...
(Since I don't have any x86 boxes handy, I'm just going to have to trust someone else to try it...)
Am I part of the core demographic for Swedish Fish?
It's too bad with all these things you "heard" that you didn't happen to hear that programs are written for environments other than Windows (or Linux, Mac OS, etc), and for devices other than PCs. It's unfortunate that you are so in the dark that you don't realize that there are entire industries that rely on devices that have tiny fractions of the memory and processor speed that you ignorantly assume that we all have access too. You probably have no idea how often you are affected by devices that run 100 times slower than the desktop PC you gave as an example, or also have 1,000 times less RAM. On some of these devices C is the most advanced language you can get short of writing a compiler or interpreter yourself.
Sure, pissing away storage space and waving a hand at execution efficiency is fine for some circumstances, but sometimes it's a luxury you can't afford. The world of software development is far bigger than the tiny little niche of programming you've been exposed to.
I suggest you use some "real" perspective, and reevaluate what a "real language" is.
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux
The smallest Linux ELF binary to print ’Hello world!’
You do realize he said "real" programs. Your hello.com is not exactly what he was referring to.
"OOP makes people lazy and gives them less of an understanding of what's actually going on."
I've noticed that people who critise OOP rarely understand what it is and tend to think it's tied to a particular type of language. OO is a way of thinking about a problem at a higher level than functional decomposition. You can code an OO solution in whatever language you like. Done properly it leads to elegant solutions eg; many of the examples in K&R exhibit the features of OO design and they were created before the term "object orientated" was coined. I assume when K&R used function pointers as elements of a struct they "understood what's going on", right?
"All that OOP code you write gets translated back into something procedural, you know."
Perhaps that's because...you know...OOP is procedural.
And did you exchange a walk on part in the war for a lead role in a cage? - Pink Floyd.
Yeah, but the 45-byte program doesn't say "Hello World". In fact, there's no example that I can find in TFA that outputs that message or any other. So the summary is incorrect on its face. TFA doesn't show a simpler "Hello World" program; it doesn't show any sort of "Hello World" program at all.
Exactly. Sure, the initial example was what it says on the tin; a simple 'hello world' in C. Through the iterations, though, it lost every single part of that. I'd argue that the final implementation wasn't "simple" in any way except byte count, given that it required some in-depth knowledge of, and then bending of, the ELF spec. The final implementation was not simpler (to a human, given that it required some in-depth knowledge of, and then bending of, the ELF spec). It was not "hello world" (it just returned an integer), and it was not in C.
:(
False advertising.
Rampant carbon sequestration destroyed the Dinosaurs' tropical paradise. I'm here to help repair the damage.
I'm not entirely sure I understand the significance of this.
So she shaved a few bytes off of an executable. It takes my 2010 Internet connection roughly 0.003 seconds to download those few bytes.
Also, if I understand correctly she shaved off a more or less fixed number of bytes, not a percentage of the original file size.
In other words, if she performed this trick with a large and complex piece of software that generated a 1Mb executable, she'd still shave off a handful of bytes, no? Is that worth the effort? I get that it's interesting from a hobbyist perspective, but in the real world, it's rather insignificant if you ask me.
Honestly no one probably ever conceived of someone writing a program that didn't use libc, because who would really not need parts of it? If you're not writing something to the screen or a file your program is not really doing anything, and both of those operations require libc. A program with no output is one that is saying "Hello World" to itself silently and then exiting at some point. Everything that it did during its execution might as well have been skipped, because it has nothing to show for it.
On a decently configured modern system using a less than modern filesystem. Which isn't really the best kind of decent configuration for all situations.
say "hello world"
Maybe check out the demo scene where 512-byte, 1k, or 4k productions are common?
"Give me six lines of C++ code written by the most competent programmer, and I will find enough in there to hang him."
After reading the article, there's only one conclusion:
Linking stuff using gcc is horribly ugly!
If Pandora's box is destined to be opened, *I* want to be the one to open it.
Could you post an older webpage to the front page of Slashdot?!
Geez, this thing has been around for frickin ages..
It's in the middle, next to the link to the Japanese page. The author got a 57 byte Hello World, and compares it to the older version by the Japanese author that was 58 bytes. The 45-byte version just strips out the string.
Slashdot: where don knuth is an idiot because he cant grasp the awesome power of php
One of the earliest machines I learned programming on only had 256 bytes of memory.
You lucky bastard.
My parents could never afford such computer. I had to learn programming on a computer with only 1 bit of memory (Yes that's right: 1 B I T of memory!)
Those were the days. And you tell the kids these stories and they won't believe you...
Your problem is that you are detailing the pros of dynamic linking and the cons of static linking, but not detailing the cons of dynamic linking or the pros of static linking.
Dynamic linking has put 3 different versions of VC's runtime on this computer in front of me, and thats starting from 18 days ago with a fresh installation of Win7/64.
Also, you seem to think that its the OS's job to maintain C libraries? REALLY??! You know that C is just a programming language, right? That there are various competing compilers, right? Each with its own libraries, right?
"His name was James Damore."
Later on, I will have been going to be sent but another AC will come back afterward to stop vtcodger (957785) from linking to The Source before you have reason to send me. You don't remember because back then it was only a prophecy but now, in the future, the past has occurred.
Didn't you ever wonder why a "hello world" program took over 4000 bytes on a modern computer, when in 1980 a Commodore VIC-20 managed to play games in less than 4K of available memory?
Nope. It doesn't have anything to do with your computer, it's a result of the target OS you compiled it for.
Why doesnt that matter?
You seem to be focused on memory footprint, and not total footprint.
Do you ship only the memory footprint the end user will need when running your program, or do you actually have to ship the whole executable?
yeah.. rhetorical question..
Seriously.. this whole "doesnt matter" attitude is the root of the bloat problem.
"His name was James Damore."
My God, are you saying that people should use the right tools and techniques for the job at hand, rather than applying the same limited ones to every problem they come across?
It's official. Most of you are morons.
***Yeah, but the 45-byte program doesn't say "Hello World".***
Not only does it not say "Hello World", it doesn't even run. I tried it on a Fedora 11 system with kernel 2.6.30.10-105.2.23, and the last two versions of tiny.asm die with:
Killed
137
The "file" command claims that the tiny executable is "ELF 32-bit invalid byte order (SYSV)", which probably explains why.
The shortest version that does run is the 64 byte version, but, even for that, the "file" command has bad things to say: "ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, corrupted section header size".
The article makes it sound like it's something ingenious to write a 'hello world' that way or that it's about some practise that is useful for usual programs, yet it's rather just an example on how to get tiny executables due to avoiding linking with the C stdlib and still doing a bit of output. I see this rather as a demonstration of a technique that's maybe interesting for code for specific devices that require such stuff etc.
It's not about: 'Hey, I've made the most ingenious smallest 'Hallo World !' or meant as something that everyone might want or needs to use somehow, it's kind of a tutorial to write code that requires something like that. So same level as tutorials about how to hook api functions and all that in windows or other 'tricks' someone might need in some situations.
So mmh. just my 2 cents.
Not only more maintainable, but filesystems should use 4k per sector, specially on raid's for performance stuff discussed on this post. This means that in a decently configured modern system, anything under 4k will still occupy 4k on disk.
Since you don't understand filesystem basics, I would recommend that you refrain from commenting on articles about sophisticated assembly optimisations. Seriously, it's unlikely to go well for you, as we have just seen in rather spectacular fashion.
So she got rid of the stdlib library, but the program no longer actually prints "hello world" (or do anything for that matter, except exiting).
Although it's interesting to see how to get rid of 11k of bloat, the program doesn't actually *do* anything anymore... so I suppose the code is still bloated, as at this point it should be possible to optimize away
char *str = "Hello World";
as well.
I suppose if she wanted to actually print anything again, she'd roll her own printf function? Great for educational purposes, and it's a good thing that was the intention. Because in any production environment, it's most likely not worth it to spend this much effort on 11kB of bloat.
Visit http://ringbreak.dnd.utwente.nl/~mrjb/growingbettersoftware to download your free copy of the book
What's this doing on slashdot?
I've written whole projects on microcontrollers (in C) that do much, much more than "Hello World", in less than 10 kB.
1) Smaller is /always/ better, 2) Embedded people like compilers too, and resent them for not quite doing what they advertise, or /could/ do, given some twiddling. I, for example, would think it quite cool if you could arrange for gcc to actually produce those 45 bytes of program, given the right switches but as it is now, you can't.
Religion is what happens when nature strikes and groupthink goes wrong.
The whole point was learning ELF structure and why things were they way they were. Didn't you ever wonder why a "hello world" program took over 4000 bytes on a modern computer, when in 1980 a Commodore VIC-20 managed to play games in less than 4K of available memory? This wasn't a waste of time.
Yeah.
To put this in perspective: Guess how big the executable header is in 8-bit Commodore machines?
2 bytes. The absolute start address of the program. The computer opens up the file, reads where it's stored, and starts putting data to the memory from that point onward. Simple enough. Of course, there's none of this "relocation" and "memory protection" rubbish to worry about.
If you wanted to store program in BASIC RAM, you could write a stub BASIC program that basically just has one code line, 10 SYS<startaddr>, where <startaddr> points to the address past the end of the program in BASIC RAM. In total, this "header" is just a dozen bytes or so in tokenised BASIC. (Don't have the time today to test how small I can make it, but...)
The better of the more recent file system designs will pack multiple small files and other filesystem meta data into that 4k page.
09F91102 no, 455FE104 nope, F190A1E8 uh-uh, 7A5F8A09 that's not it, C87294CE no. Ah! 452F6E403CDF10714E41DFAA257D313F.
Why? Isn't the money better on the first one?
Goes to show that C is nothing but a bunch of bloatware and the c advocates nothing but a bunch of hypocrites. This will shut them up once they come to me ragging on Python or PHP again. Ha!
We suffer more in our imagination than in reality. - Seneca
I've fallen off your lawn, and I can't get up.
There were a discussion at some game dev forum a few years ago, using VS60 (which compiles to win32 exe) some person come up with a ~400 bytes exe file (doing nothing).
Using DOS, a 14 bytes program is enough:
MOV AH,09
MOV DX,0108
INT 21
RET
DEC AX
DB 65
DB 6C
DB 6C
DB 6F
DB 24
-------
14 bytes.
With INT 21 (requires DOS). A couple more if only using BIOS/INT10 (no OS), must then print each char as individual characters, cannot print a whole string in 1 call.
...besides, high-level programmers often underestimate just how big a sector embedded programming is. The $IDIOTS_PET_LANGUAGE is for a PC. Now get me more RAM and better CPU for all the devices running embedded software, that are in my sight range as I look around:
- my cell phone.
- 6 different monitors (OSD doesn't happen magically. Something remembers the settings...)
- a videoserver
- 2 cheap switches
- a regulated power supply
- a heat-controlled soldering iron
- a regular phone
- 3 PC keyboards (hey, neither PS2 nor USB protocols happen by themselves)
- 3 computer mice (optical, meaning pretty advanced image analysis)
- my hand watch
- a battery charger
- a USB hub
- a security motion sensor
- an MP3 player
- a webcam
- a multimeter
- a car alarm remote
- a pendrive.
These all were programmed either in VHDL, Asembler, or C. The phone has some J2ME code too. Think of upgrading each of these devices so much that its firmware could be rewritten in, say, Perl. Or C#.
Also, think about how much embedded programming is in every PC. Each device controller has its own firmware... my bet is any average house contains more embedded programs (in embedded devices) than PC applications on the "family PC" and stored on media.
High-level programming languages are nice and have their place, but considering embedded "a niche not worthy of attention" is a bad mistake. The proportions between amounts of server:desktop:embedded software are much closer to 1:1:1 than most "high-level" programmers are willing to admit.
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
Not only does it not say "Hello World", it doesn't even run. I tried it on a Fedora 11 system with kernel 2.6.30.10-105.2.23, and the last two versions of tiny.asm die with:
Killed
137
That could be something to do with the shorter version assuming that marking memory as readable will also imply that it's executable. This used to be true on x86 but isn't anymore.
Yep, that would be okay if you took a ready-made car. But compiling is more like car assembly process. Compiling a program is like you tell what parts should go where, you add your engine and get it running smoothly.
In this case, you tell the engineers you want a mock-up frame of bare essentials to have this bare engine you provided started. You expect them to attach the starter motor, the power from the battery, ignition switch, some frame to attach it to, and a pipe to a bottle of fuel.
Instead, what you get is a car with a complete gearbox, electric installation, steering and brake system and pretty much all the basic essentials needed to drive (no extras like AC, airbags or ABS). You didn't ask for anything of that and you wanted to use the engine to power a stationary water pump and the whole "car stuff" really gets into the way.
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
I don't know where this 'hello world' everyone is talking about is, but it sounds awfully friendly.
This used to be true on x86 but isn't anymore.
This was on an x86 (a pentium 4), so my guess is that Linux no longer ignores some of the bits that the author claims that are ignored, which is why I mentioned the distribution and kernel version.
The article was written in 1999 (note how I have to be exact by including the millennium in the year!), and corrected in '01 and '09.
The problem with demand paging is that bigger programs end up with small parts of each page that ARE used, while most of a page is unnecessary.
Someone needs to write a profiler that figures this out, and then allow gcc or the linker to take the profile to put all the actually used parts together and the unused (or little-used) parts somewhere else.
Similarly, demand paging back in '2000 (around when the article was written) caused a 7Mbyte binary to be read into memory non-linearly. All the seeking makes the loading slow. I and at least one distribution used to have a "dd if=netscape.bin of=/dev/null bs=64k ; netscape.bin $*" as a shell script instead of netscape. This would load all 7Mbytes into the cache circumventing demand paging which was much slower....
Having the important bits together in say the first megabyte would get us the best of both worlds.
Moreover, with faster harddrives we should be moving towards larger page sizes. Although the hardware has 4k pages, we should use 8k software pages adjacent page table entries are always set (almost) the same! This means that demand paging will fetch 8k at a time. Fetching a 4k page from a harddisk costs you an 8 ms seek time, 4 ms rotational latency, and .05ms for the actual transfer of the data. If we transfer 8k at a time, we go from 12.05ms to 12.1 ms. An increase of less than a percent.
On a modern system fetching this extra 4k comes at a price (besides the 0.05 ms extra transfer time). We'll have to forget about another 4k chunk of memory. However, if we achieve a 1% higher hit-rate on the just-transferred 4k chunk than on the chunk we just discarded, we'll be winning! So if we are able to evict memory that hasn't been used for say over a minute, we're very likely winning over the current strategy.
For F*ck's sake, you idiot. DOS was never "bare-metal".
This is a lame excuse for writing bloated code...
"Anyway the compiler will f*ck it up, so why bother ?"
mov ah,9
mov dx,108
int 21
retn
db 48, 65, 6C, 6C, 6F, 24
At the time of writing this comment, I'm disgusted by the amount of flames rated +5. "Haters gotta hate", sure, but haters gotta be modded-up? What ever happened to constructive criticism? Of building some better explanation from a weak article?
I come to Slashdot for the interesting and insightful discussions. Criticizing without anything constructive serves only in inflating your own ego.
I believe this article is interesting. Though it does cover part of the same subject as the Whirlwind Tutorial, it doesn't duplicate it. It provides insight in the backstage of C programs which many programmers aren't aware of. I certainly wasn't aware of it before reading the whirlwind tutorial a few years ago, and there's always a new generation that can learn from it
This is definitely a smaller program, but I wouldn't characterize overlapping functionality with header address space in assembley "simpler."
If you have to ask questions about how much memory your program uses, you can't afford it.
In Java, the simplicity is that you write code (preferably something abstracting someone elses code) and don't let little things like memory and performance bother you.
Now back to reality, it's interesting as an experiment, but in all practicle purposes for what? If you are running on an OS such as linux or windows, use the services they offer you. Why invent the wheel? Certainly, why write in assembly code? Now if you are running on a AVR or the like (yes, I do that) I can see why some would go and use assembly, but still, even then I use C/C++ It's amazing what you can stuff into 32K of flash and 2K of ram
-- Many men would appreciate a woman's mind more if they could fondle it
c:\ xxx>debug :001C
-a
mov dx, 100
mov cx, 000D
mov bx, 1
mov ah, 40
int 21
mov ah, 4C
int 21
-f 111 "Hello World"
-a100
mov dx, 0111
-r cx
-n c:\ xxx\ hello.com
-w
-q
c:\ xxx>hello.com
Hello World
c:\ xxx>dir hello.com
03/18/2011 11:29 AM 28 HELLO.COM
What do I win?
These days, costs of development and deployment, not runtime memory usage, are the limiting factors in software development.
So, how's the weather in Redmond today?
My (hello) world brings all the boys to the yard,
And their like
It's smaller than yours,
Damn right it's smaller than yours,
I can teach you,
But I have to charge
Yes, and many people here are all to ready to let the key only activate the starter, and not the airbag, traction control and radio too, and call them bloat to boot.
Real programmers know that the code is also the comment
Where else than Digi-Key? With Mouser Electronics, shipping to Canada is much higher than with Digi-Key.
Where do you buy parts, Mr. Smarty Pants?
You have to explicitly enable function-level linking with gcc. Compile your source files with -ffunction-sections -fdata-sections, and then pass -gc-sections flag to ld (-Wl,-gc-sections if linking with gcc). This puts every function into its own .text.section and allows the linker to prune the ones that are not referenced. The remaining ones are coalesced into a single .text section.
I think this is largely a function of how OOP is taught- including the languages used to teach it. Too many people start with Java and its "everything is an object! but they're not all first-class objects! and we're going to try to hide it all from you even though you have to know the details anyway!" design principles instead of a language that either a) cleanly mixes OOP in with procedures *not* tied to objects, or b) is a fully OOP-supportive language in which everything really is a first-class object.
Instead we get "Java is OOP, C is not" when in truth you can easily do non-OOP programming in Java and OOP programming in pure C (and, as you pointed out, a lot of C from quite a ways back shows a lot of the features of OOP programming).
The ringing of the division bell has begun... -PF
'This subsection of the Muppetlabs website is maintained by Brian Raiter (aka Organic Worker Drone BR903), who is the author of the contents where not otherwise indicated. '
Since no one else was indicated that I could see. (And, yeah, was kinda fun to reread this after all these years) seems odd to assume Brian is a she...
-- perl -e'print pack"H*","6e656d6f406d38792e6f7267"'
C++ is not "better" than anything. C has its place, as does Java. C++'s place is the trash.
perhaps I am missing something, but I never thought of "Hello World" as program. It is more or less a concept or an experiment I use to get my first grasp on a language or tool chain. It is constantly rewritten so that each time I use it, I gain a solid understanding of the basics of how to program in a specific instance. The author is simply applying this tool to assembly.
you don't eat crackers in the bed of your future--or else you'll get all scratchy
... using RSX emulation. I can no longer remember the compiler we used . Maybe Whitesmiths? But I do remember needing to implement a really basic :-) stdio library.
By the time we were finished with the project, we had implemented a client-server data management system (it could not be called a database) that supported transactions, ordered indexes and never lost a record through years of operation.
The company ended up replacing a PDP-11/73 with a SparcServer 2 in 1990, I think.
Whenever a file is stored on a hard disk the space it takes up is normally 'rounded up' to the next larger multiple of the disk file allocation unit, which varies somewhat depending on the filing system and the size of the hard disk in use. But a common figure nowadays is a 4K allocation unit. So even a 0- or 1-byte file will probably take up 4K. If your disk uses 32K allocation units (an extreme case, as far as I can tell from a quick check) then you could almost triple the size of this hello world file without using any more space. So in practice, trying to make one already tiny file even smaller amongst the hundreds of thousands of other sub-4K files also present on a typical system is completely pointless.
Here we still program in C (I don't, but others here do) because if we wrote in something like .NET, Ruby or Python the executable would be so much bigger and the binaries wouldn't fit on the device hardware. So sometimes having something 'closer to the iron' is better.
Then again, when telling a device how to servo, string interpretation is seldom of high concern.
No, it's the OS's job to maintain an interface to its functionality and that is done, for historical reasons, via the C standard library on POSIX-type systems. Windows uses another set of libraries as the main interface, upon which the C standard library is built. I find the idea that you can make system calls directly on Linux a bit strange. It's really the odd one out. All other client-server models require a library on the client end. And almost every program on Linux does use such a library. So why the fuss?
Additional points:
But you have to remember, C isn't just another programming language. It's pretty much the closest thing to assembly without actually being assembly. So it's a darn good choice for the system libraries because any other language can easily access the interface. If the interface where in some more complicated language, it'd be a pain and probably require a lot more overhead.
Competing compilers can still use the same C standard library, so that concern is irrelevant. If they really really want to use their own special C standard library, they can still do that...but they have to make system calls via the system one. Big deal. One extra library (which you don't have to use if you don't want that kind of bloat).
Being happily ensconced in the bare metal world (Cortex-M3: Nice machine), I would be careful about using the word "inferior".One starts to count bytes and k's when the *entire system cost* is under $25.00 including power supplies.
With that being said, most embedded developers do the bulk of their work in C and on occasion C++ (with great care), with very little assembly support. For what it's worth, most CPU developers are aware of the transition to C and have done an excellent job of making it possible to do almost all system management, including exceptions/faults/priority/interrupts, in C with very little ASM. Where ASM does become necessary, it's usually expressed in a function-call form that keeps the C code neat and clean.
You must be new here. Car analogies can only be used on Slashdot when they are totally flawed for explaining the topic at hand. Your apt, informative car analogy is a violation of Slashdot's cultural mores.
--Obyron
It is a flaw (including libc), but the fact is, we very seldom are going to create programs that aren't going to require the inclusion anyway.
I'll admit it is embarrassing because of the historical efficiency of 'C', but a program that prints a simple message or exits with an error code is not a real-world application nor a real indicator of how efficient the language is for actual application development.
It is a good for a yuck though.
Yours does more than the article did. Yours actually prints hello world. Hers just returned 42. So I am sure you can do even better...
If it just has to return 42...
C:\>debug
-a 0100
0D3D:0100 MOV AH,4C
0D3D:0102 MOV AL,2A
0D3D:0104 INT 21
0D3D:0106
-rcx
CX 0000
:6
-n ben.com
-w
Writing 00006 bytes
-q
C:\>BEN.COM
C:\>echo %ERRORLEVEL%
42
...besides, high-level programmers often underestimate just how big a sector embedded programming is. The $IDIOTS_PET_LANGUAGE is for a PC. Now get me more RAM and better CPU for all the devices running embedded software, that are in my sight range as I look around:
- my cell phone.
- 6 different monitors (OSD doesn't happen magically. Something remembers the settings...)
- a videoserver
- 2 cheap switches
- a regulated power supply
- a heat-controlled soldering iron
- a regular phone
- 3 PC keyboards (hey, neither PS2 nor USB protocols happen by themselves)
- 3 computer mice (optical, meaning pretty advanced image analysis)
- my hand watch
- a battery charger
- a USB hub
- a security motion sensor
- an MP3 player
- a webcam
- a multimeter
- a car alarm remote
- a pendrive.
These all were programmed either in VHDL, Asembler, or C. The phone has some J2ME code too. Think of upgrading each of these devices so much that its firmware could be rewritten in, say, Perl. Or C#.
Also, think about how much embedded programming is in every PC. Each device controller has its own firmware... my bet is any average house contains more embedded programs (in embedded devices) than PC applications on the "family PC" and stored on media.
High-level programming languages are nice and have their place, but considering embedded "a niche not worthy of attention" is a bad mistake. The proportions between amounts of server:desktop:embedded software are much closer to 1:1:1 than most "high-level" programmers are willing to admit.
The PIC micro-controller pic18F series and above have several nice C language tools that make embedded programming pretty nice.
My off-grid solar battery energy storage monitor using a pic18f8722 controller.
http://www.flickr.com/video_download.gne?id=4252648643
Early build construction slide-show.
http://www.flickr.com/photos/nsaspook/sets/72157622934371746/show/
In GOD we trust, all others we monitor.
It does make you wonder though. It added ~11k to the simplest of programs. Where else is it tacking extra junk in?
People really expect their linkers to do wizard things. Yet they are still pretty simple things. They are general tools that do what we need pretty well. But when you see this you scratch your head and say 'hmm maybe it could do better'. That program should have been emited from the compiler should have been no more than 200-300 bytes. Instead it was nearly 11k... Even with O3 and a few of the tweaker options she was getting about 2k and that was before resorting to asm.
People also expect wizard things from the O3 switch and a few other ones. They do quite a bit. But not nearly what the magic everyone thinks happens. With some compilers you can have an if(0) {...} block of code and the compiler will dutifully still include the branch and the code in. Some are smarter than that. But do you *really* know unless you look? How many people actually look or just assume? Then you have the other group saying O/arch switches are useless and dont do anything when that is false. They dont do much but they do help and in some cases quite a bit. Then you have another group that is afraid of the O switch saying it emits bad code. The number of times I have seen that in 20 years I can count on 1 hand and it is usually fixed in the next point release.
With your 'who cares' attitude. Code will get worse.
"the days of programming bare-metal on DOS"
If you're using DOS, that's not baremetal.
Actually, embedded software probably makes up the VAST majority of the entire software market. Microcontrollers are everywhere, in your TV, your microwave, dozens in your car, your watch, your phone, your electric razor, everywhere.
MIT students try to teach your grandmother to suck eggs.
The Kruger Dunning explains most post on
This was on an x86 (a pentium 4), so my guess is that Linux no longer ignores some of the bits that the author claims that are ignored, which is why I mentioned the distribution and kernel version.
Depends on which x86 processor. Apparently, some Pentium 4s have the NX bit and can mark pages as readable but not executable, whereas others don't.
The really small Linux programs are less like a normal car and more like a Service Car. These Service cars start with a pull cord like a lawn mower, no ignition needed. Both are niche items with practical justifications for their creation that owe their current existence to labors of love (one of parts the other of publishing.)
These cars also use a handlebar instead of a wheel and double as a trailer when being pulled. So, perhaps not unlike the typical Linux application at all.
"You cannot have a General Will unless you have shared experiences. You cannot be fair to people you don't know."
Not to mention that I have yet to meet the programmer, embedded or otherwise, that can beat the compiler when it comes to optimizing, for space or for speed. Even for my bread and butter, embedded systems, I have yet to have to touch assembler or microcode. Everything is in C and C++. Granted, most of my "embedded" systems are more comparable to desktop powerhouses of 5-10 years ago. But even when a friend and I were making software for an HC11 (where we had to make our own pseudo-filesystem that had to find the sweet spot between reducing writes to flash memory and trying to protect privacy), we wrote everything in C. We just wrote it *smartly* and used good algorithms. The result: entirely readable *and* efficient code. The simple fact of the matter is that unless someone is *hyper* competent and *extremely* familiar with the underlying architecture, they will most likely not beat the compiler for optimizing. If they claim that the higher level language adds too much bloat (such as C of all things!), then they are probably just not qualified to design algorithms or program in the higher level language.
Nathan's blog
If a programmer doesn't know this, they aren't competent to be programming, much less programming in spaces that may be critical (such as embedded). Don't use wizard code you don't understand. And it's "crt1.o", BTW.
Nathan's blog
The code you have provided a link to will not run on Windows 9.
Yeah, and this gets to the point of my basic criticism: Writing the program in a different language is not an example of a simpler version of the program "in C" (as was advertised).
Criticising C because its object files are larger than carefully-tailored assembly code isn't a relevant criticism. C wasn't designed to produce the world's most compact object files. It was designed (look it up) to produce reasonably small programs that are reasonably portable.
That portability part is extremely important; it was why the language came into existence in the first place. K&R (and friends) at Bell Labs had written most of their first version of unix in assembly language. Then they got a better machine, and wanted it there. They faced a huge rewrite job. They decided that they wanted to do this only once more, so they would do most of the rewrite in a higher-level language. They had the B language, which was fairly good for doing the low-level things needed in an OS kernel, and as they went, they modified it so that they could rewrite more of the kernel in what they finally renamed "C" (because it had become a somewhat different language than B).
They admitted right from the start that C didn't produce code quite as compact or fast as they could write in assembly. But they decided that it was a worthwhile tradeoff, because new machines were coming along eery few months, and they got quick porting from this new higher-level language.
So saying that we can do better (i.e., smaller and faster) in assembly isn't very interesting. We've known that since the 1950s when the first "higher-level" languages were developed. Proudly announcing the fact now is just silly, and makes you look like some sort of idiot.
Comparing the results of different compilers and/or runtime libraries is a lot more interesting. Smaller and/or faster code is interesting and useful. But it's only one of the criteria for "good" code. Telling people how to minimize the size or maximize the speed of code in language X is useful for people using X. But saying "rewrite it in assembly language" is mostly just silly. Most of us know that, and we're not gonna do it very often, because it violates most of our other criteria for the code we're writing.
(Lately I've been writing a lot of code in perl, python, and other language that are a lot bigger and slower than C. There are often good reasons for doing this. Sometimes I give up and redo something in C for performance reasons. This article does nothing to teach me about doing that better. It's been many years since I've had a valid reason to rewrite something in assembly language. Portability is always more important than what assembly would give me. But YMMV, of course.)
Those who do study history are doomed to stand helplessly by while everyone else repeats it.
To make the C program which displays "Hello, world!" smaller, don't display "Hello, world!" and use a different language.
I appreciate the obsessiveness, but it kinda misses the point.
Can we get a "-1 Wrong" moderation option?
It's almost like you guys are a subsubculture of programmer, to the point where many of you guys come off with the general attitude of being superior, when in fact, neither approach is superior, just different based on the situation.
To be fair, you have to be really damn good to write software for embedded systems, while you just have to be OK to write normal software. Hell, you don't even have to be OK; just read some of the crap in The Daily WTF.
Which does, in fact, put them a cut above most, but not all, programmers that develop in a higher-level language. And I say most because there probably are programmers that are even better developing in a high level language than embedded systems programmers, simply because the complexity actually increases with the increase in expectation that comes with coding in a high-level language. It's one thing to employ tricks to make something small and fast. It's quite another thing to employ the right tricks towards the same goal, but keep everything organized, readable, and maintainable.
So don't feel too jilted.
"If a nation expects to be ignorant and free in a state of civilization, it expects what never was and never will be."
Hmmm ... It looks like I should have hit Preview once more. ;-)
Funny thing is that my last Preview didn't have that problem with the runaway <b> tag. I went to the end of the text and added a bit more text, which should have been in the non-bold part, and hit Submit. Then I noticed what had gone wrong.
I wonder if I accidentally fat-fingered something that somehow edited a remote part of the textarea window. Or maybe it's just another of the many weirdnesses in Slashcode 2. I have seen it get very confused when I try some rather simple HTML tricks. But a </b> tag seems too innocuous to screw up. Oh well, guess I'll never know.
OK; that looks good, so I'll hit Submit ...
Those who do study history are doomed to stand helplessly by while everyone else repeats it.
The real code needed a tiny loop to load bytes and write words, something like this:
; DS:DI -> Message to write
; CX = length of the message
; ES:DI -> 0B800h:0 (or any other screen offset)
; AH = 8 (or some other reasonable attribute)
next:
lodsb
stosw
loop next
Terje
"almost all programming can be viewed as an exercise in caching"
I remember a simplified Tetris clone on DOS that took exactly 100 bytes. It ran in text mode, with the drawing ASCII characters (i.e., ANSI-art style).
tmegapscm
In Soviet Russia, Windows throws out YOUR LAPTOP!!
Sure, and where, other than a VIC-20 will that 4K program run?
Nowhere.
To put this in even more perspective, DOS .com files have no header whatsoever. It literally just loads the file in memory at segment boundary + 0x100 (remember, it's 16-bit Intel architecture in all its glory) and jumps to the first byte of that. The extra 0x100 bytes are for OS runtime header for the application.
The result is that not only you have no relocation, but the size of the binary is limited to 0xFFFF-0x0100 bytes.
But, hey, it's simple.
The fundamental difference between embedded software development and developing applications for PCs is this: embedded software can have no bugs. Unless the device has built-in flash or other mechanisms for upgrading, you absolutely, positively must have the software perfect before the device ships, cuz there ain't gonna be a version 2.0. In embedded software, it is the code that brings the hardware to life, and any bug effectively kills it. When a 3-year accidentally presses the "talk" and "burp" buttons at the same time on her Suzy Flatulence doll and it bursts into flames, not only are you totally fired for not properly safety-testing your code, but the company that you used to work for is totally hosed, along with all your coworkers - and of course all the crispy kids that owned the flaming Suzy dolls.
Or ask any owner of a car that has a drive-by-wire accelerator whether they think a bug or two is OK.
Sure, PC application programmers can worry about bugs, but they know that deep down, if there's something wrong with the hyperlink resolution code in their browser app, that they will probably get a chance to fix it. Not so with their embedded developer brothers - when one of *their* products ship, it's usually a scrotum-tightening, make-or-break deal.
And that's why I'll hire an embedded systems programmer over a .NET GUI weenie any day.
Back in the old days, I recall writing TSR (terminate and stay resident) DOS programs in Assembly language. The code needed to be very tight to fit into a PC's teeny RAM (64K system total?) Great learning experience, but the ROI on time invested, unthinkable today.
Hate to break it to ya, but many C compilers dont use compatible ABI's.
.. and this is why the C standard library is an outrageously terrible interface to the OS: it dictates what features the calling convention must support, instead of the OS dictating what the convention will be.
If you've been in the Linux world for awhile, then you might know that Intel's C compiler (and anything it produced) wasnt compatible with GCC until version 10 or so.. so yeah.. about that standard library sharing...
In the Windows world, C compilers default to CDECL but the standard API calling convention is STDCALL.
Why do C compilers on windows default to something that isnt the standard for the platform? Its because the C standard library has a couple functions which require a CDECL or a CDECL-like calling convention in order to work, such as printf()
"His name was James Damore."
Your soldering iron, power supply, battery charger have computers in them? Must be pretty advanced. All of these usually just have some kind of comparator inside and basic logic ICs - unless they have menus with settings, etc
from 09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0
to 45 2F 6E 40 3C DF 10 71 4E 41 DF AA 25 7D 31 3F
1. run w8loss.exe against your executable to strip it. (I just love that name :-)
2. recompiling using the tiny memory model, shouldn't you call it hello.com?
Oh, this isn't C it's assembly, so the title of this thread is all off. It should be how to rewrite your C code in assembly to optimise your code.
Only 'flamers' flame!
Does slashdot hate my posts?
To put it as a car analogy: What she found is that turning the key to start doesn't just activate the starter, it also activates the airbag system, the traction control, and the radio too. And if all you want to do is start the engine to prove that it runs (ala Hello World!), then it's kind of silly to lug around all that extra "unnecessary" crap too.
No, a better car analogy would replace the output of "Hello World!" with having the car's headlights turn on.
An old timer would likely just hop in the car and turn on the headlight switch.
A newer car user would hop in car, insert and turn key to start engine (and all that that involves), then apply the brakes to shift to drive. The car's computer would then automatically turn on the day time running lights. But, on some models, the running lights are not the headlights, but are the turn signals, so the "headlights" output would be in orange instead of 3100k white.
Unfortunately, the two opcodes were as follow: 0 = No Operation 1 = Shutdown
Well, you can shave off 2 or 3 bytes by using "int 20" instead of "mov ah, 4C / int 21" :0015
You can save a few more bytes by using the function 9 of int 21 routine too since it has a simpler calling convention.
From memory (it's been a while) I think it's only ah=9, and dx=offset. The downside is you have to terminate the string with a '$' sign.
So the correct shortest Hello World! is:
c:\ xxx>debug
-a
mov ah, 9
mov dx, 109
int 21
int 20
-f 109 "Hello World!$"
-r cx
-n c:\ xxx\ hello.com
-w
-q
That should shave off a nice 8 bytes which you can use elsewhere :p
You can even shave off one more byte if you use the fact that on the stack is the return address 0000, which is the start of some program data block which conveniently starts with "int 20", hence your program can use the 1 byte "ret" instead of the 2-byte "int 20" - but that's kinda hacky.
He's right, you forgot to mention that is has TWICE as much EPROM memory, positively cavernous at 512 12-bit words.
(heh those chips bring back memories, way back in 97 I used to use the a lot of those Microchip parts 16c, 18c, 17c etc families)
It doesn't. It imports the modules you reference. You do realise that a static library is nothing more than an archive of object files? Read the man page for 'ar'
Nope! Now, hand me that pickaxe, I need to dig myself a memory upgrade.
http://df.magmawiki.com/index.php/Computing
I use Windows... like a two dollar wh.. why don't I just go ahead and not finish that sentence.
Sure, the hello.com example is obviously the trivial case, but the same sorts of bloat it demonstrates apply all too easily on larger scales as well.
I am currently running 47 processes on my WinXP box. Those include:
The list goes on, but you get the point. It is crazy that such simple applications should take multi-megabyte footprints (and those are the working sets I'm talking about, not all the stuff that's paged out).
Does this matter? Well, yes, when all the trivial background stuff adds up to nearly 1GB of RAM. That is significant even on today's PCs, if you want to run an application like a high-end game or graphics package that actually needs a lot of RAM to hold the data to do its job. And of course, the more you load up and possibly page out, the slower the system boots and applications load, the less effective caches become, etc., so there is a performance hit as well.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
That initial 11kB is pretty fat. MarcsForth, a bloated version of Forth 83 without any attempt at optimization uses 11.1kB (including the word headers, which is like keeping the whole symbol table in the executable). On the other hand, the reference manual tips the scales at 310kB.
Just as interesting: it was finished in 1987 and runs without a glitch under Windows XP.
I'm a Programmer. That's one level above Software Engineer and one level below Engineer.
run w8loss.exe against your executable to strip it.
w8loss.exe doesn't come with Turbo C, at least not with the version that I have here.
recompiling using the tiny memory model, shouldn't you call it hello.com?
I kind of thought so too, but the compiler named the executable hello.exe.
If you're a zombie and you know it, bite your friend!
The folk who do embedded code can easily do the high level stuff; the converse is not true.
The one problem with programmers who've been working close to the metal is that when they do have something to do at a high level (in bash, for instance) they tend to spend too much time getting it just right.
I'm a Programmer. That's one level above Software Engineer and one level below Engineer.
It was a big letdown finding out this wasn't the final optimization to Hello World, transforming it from a junky affair of #include and printf (or puts) into a highly-refined program of half the source text. The headline really had me rekindling my youthful yearning for a smaller Hello World. I am so let down right now. I'm calling a friend.
True, but that's no excuse for a compiler/linker to bring in a library that's not needed.
I'm on the fence about this. For the VAST majority of uses of gcc, you are going to want to include stdlib and friends, and for the other uses, there's a flag to disable it. Now there does not seem to be a way to generate mind-bendingly small executables with gcc, but I'm unconvinced of the need for that either :P
On second thought, I think gcc-arm will probably generate super-tiny executables with the proper flags, it just won't run on x86 linux...
So anyway, the common use-case is x86 system with full-sized linux system, for which the common use case is programs that will want to use stdlib stuff.
To all you people complaining about the original article being old news from 1999... port it to a modern 64-bit architecture!
Needs a newer nasm or yasm:
http://www.tortall.net/projects/yasm/wiki/AMD64
Of course, to win the game, you'd probably want to go the other way and backport it to a 16-bit or 8-bit processor.
Anyway, loved the article... I didn't like the way most CS classes glossed over these kinds of admittedly mundane but practical matters. I am interested in knowing what every single last damn byte is doing there!
If gcc needed to be as samll and compact as possible, that would be a good way to handle this. However, that's not true, and I see no reason it shouldn't check to see if libc is needed and link it in if, and only if it's going to be used, just as it does with every other library.
Good, inexpensive web hosting
Tell me about it. I've been playing around with PICs lately and I've recently compared a compiled C program (mikroC) to a program that I wrote myself in assembler. Its task was simply to output "Hello World!" to a HD44780 LCD module, and whereas I could suffice with about 20-30 lines of code, whereas the compiled program required about 120 lines to do exactly the same thing!
The compiler created about 10 subroutines out of thin air. It was a mess!
But it also makes everyone else who likes binary compatibility, and Mac OS X historically getting faster with every release, extremely happy, by allowing the interface between the kernel and libc to be changed, without breaking their applications.
If you statically link, you can't do that. That's great, if your OS has pretty much no real commercial application base, and you are a technical enough person to "just recompile everything from source", but it's not so good when you are talking about an OS where commercial software is very important to customers. Customers who are either non-technical, or who are technical, but think recompiling something that was working just fine before the OS update is a complete waste of time.
This is a strawman, there are various approaches to this problem that do not involve locking down access to system calls to a single channel. You also make several incorrect (or at least incomplete) assumptions about the alternatives.
1. The USER must re-compile software if the OS changes.
This is not true, in the Linux and BSD worlds, the majority of the compilation happens at the distribution level, end users generally don't mess with it unless they WANT to. Additionally the provider of the software can compile the software, though admittedly this is difficult if your project targets many environments.
2. Commercial software requires binary compatibility across OS versions because it can't be rebuilt.
This is a false dilemma, see below points.
2a. Commercial software must be compiled by the authoring organization.
There are commercial software suites that provide source to customers, it is only the massive level of paranoia about preserving their "precious IP resources" software houses have that keeps this from being more common. It is something THEY want, not the customer, so why should the customer end up paying for it? (and this does not mean that the user MUST be the one to re-compile, an intermediary of some kind could just as well do it.)
2b. The authoring organization can not recompile and redistribute software if the OS breaks binary compatibility.
Linux and BSD distributions do it, and they aren't "real professionals" right? In my experience the only reason commercial software houses can't handle it is because their development methodology is deeply broken and can only be coaxed to work properly for a short time around a launch window. In other words, the inability to provide deliverables that will work on multiple platforms is another self-inflicted problem, once again, the end user should not have to pay for this.
You have some valid points, and I think locking down libc as being essentially part of the OS is one solution (hell, it's come up on lkml from time to time), but I think you vastly overstate your position.
w8loss.exe shipped with various Borland products. I know it came with BC++3.1 (which I upgraded to from Turbo C 1.0) and Delphi. If you have either of those, you should have a copy.
A few years after I bought Delphi 1.0 ($500) Borland allowed it to be released as a cover disk as part of an effort to generate buzz for a later version.
It *might* also be sitting in a kylix distribution (oh, the pain).
Actually, I believe the point is to print "hello, world".
Actually, her point was to just return an exit status of 42.
However, if you really want to see hello world, add 37 bytes, and use this.
Yes... but you surely realize that embedded C for microcontroller is significantly different from most "high level" languages?
Imagine a seasoned Enterprise Java developer switching to the required mindset...
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
No, I still want to see 'hello, world'. Your link doesn't have it right either.
No, I still want to see 'hello, world'. Your link doesn't have it right either.
So, what exactly is wrong?
and a modern PC it doesn't matter at all.
This is EXACTLY why we have to constantly buy new hardware, and upgrade the CPU/RAM to do the same exact tasks were were doing with 1/100 the power 5 years ago....
To reply to your specific points...
I'm going to paraphrase for brevity; forgive me and correct me if I misrepresent your points:
(1) The majority of compilation happens at the distribution level
I think this is addressed by my point about whether or not your platform has a lot of commercial software, or not. Commercial software comes from a huge variety of vendors, not a single vendor. In the "BSD distribution" or "Linux distribution" model, yes, the distributor will likely be compiling up all the packages they can possibly make work. The problem with this is that the vast majority of these are not going to be commercial packages.
You can maybe argue that commercial software doesn't have value to you, but that is simply not true for the majority of computer users. It's almost universally true for non-technical computer users, or you would be seeing greater desktop penetration of a BSD or Linux distribution, and some hardware vendor wanting to drive down either their COGS (Cost Of Goods Sold), to increase their profit margin, or to lower their price point. Other than a few luke-warm toe dipping by a couple of vendors who have not followed through with jumping into the water wholesale, this simply hasn't happened.
(2)(a) Commercial software could provide source code, but does not because of paranoia
This is false. Commercial software exists because there are margins in it. I've been in commercial software since the 1980's. Source code has always been available for a price, it's just not a price the market will bear. I've been party to a large number of contracts, such as my company being a designated vendor for AFCAC (Air Force Computer Acquisition Center) contract 451, where source escrow was a requirement. Source escrow is surprisingly easy and cheap to add to contracts between vendors and end user organizations.
The other factor here is that a vendor can not trust a third party to do the necessary due diligence with regard to compiling other code correctly, or testing it to make sure it meets specification. It can't trust that there will be timely security and other updates to the software when the vendor mandates them. It can't trust that the third party will have the necessary capitol resources, such as machine rooms full of machines, necessary for long term testing for the software and hardware combinations they intend to release on.
Again, you can maybe argue that if the vendor did test automation development at an order of magnitude higher than most vendors currently do (with the associated increase in cost to the consumer), that they could provide the necessary testing resources. And you could argue that mandating ISO 9001 certification for the third party, and doing compliance audits to make sure that the quality assurance model isn't breaking down anywhere, could cover the potential quality issues for the third party on which the vendor is taking their reputation. The costs involved would drive the software costs to the consumer far higher than single-source. This would not only put the vendor at a competitive disadvantage with regard to other vendors, it would fail to address the increased latency in the supply chain for things patches for zero-day exploits.
(2)(b) Binary compatibility issues can be addressed by recompilation if commercial software houses just fixed their methodology
With respect, I disagree. I addressed the process latency issue and affirmative quality requirements in my response to (2)(a), above, so I won't repeat myself on those points.
In regard to "fixing the development methodology" to enable supporting multiple platforms (and I take that to mean incompatible versions of the same platform, not just cross-platform), you're wrong. Correct software development methodology in that environment requires that you establish interface contracts between components and software, such that recompilation is easily accomplished.
No one in the Open Source world is willing to do this to any approximation of the r
it has to do with people generally not caring about 11k.
Um, isn't that exactly what bloat is? "Who cares if it's n bytes, it works!"
Oh, you care about disk space? Ah! Indeed I don't... :-)
Disk space is some 100 times cheaper than RAM. It's the bloat that ends up in RAM that means you have to buy 2G or 4G of ram in a modern machine to make it work. I can still make a (server-) install in under 1G of disk space, but running a desktop in under 1G of RAM is a performance problem.
That's the bloat I care about.
Let me follow this up by saying that I don't want to discourage anyone from /learning/ how to program, especially the GP, as he or she seems interested enough in it to search out things like this. What I mean by "they aren't competent to be programming" is that until someone is familiar enough with the language and underlying hardware and software, they shouldn't try to pass off their programs as the most reliable or efficient things around. Things like the The Pragmatic Programmer are especially cogent to becoming a better programmer, even if you only take away this one lesson: understand the abstractions you use. The layers of computing have been built and tested for decades, and most of the time they make sense and make your life easier (that's what they are *for*). But make sure you at least use them properly, and the surest way to make sure you use them properly is to *understand* them, eg, know that GCC will attach a whole bunch of stuff to your program (because almost all programs use it) that you might not need.
Nathan's blog
http://www.google.com/search?q=minimize+exe+size - a mere 1/2 million hits? An Anonymous Coward, indeed :)
It's good to see Linux catching up; to think, PE executables are... PE executables!
What has been will be again, what has been done will be done again; there is nothing new under the sun
Theres no reason perl or C# couldn't be used on those devices. The language doesn't define how much resources it requires, its just a way to describe what you want do so that it can be translated to something the CPU can actually understand. I most certainly can use C# on my phone. Its one of the preferred languages for WinMo, and mono lets me compile to a static binary for things like the iPhone which don't allow for dynamic runtimes.
The problem with higher level languages is that the compilers and VMs for them are rather shitty at optimizing things, which is fine where they are used as they aren't used for performance related bits nor are they used on light weight hardware.
If someone wanted to bother investing the time into making a extremely intelligent compiler it might change.
It won't happen because the people capable writing code of the quality needed on these devices prefer to work in assembly so they have total control and know exactly whats being done.
Persistent Volume manager for Kubernetes - https://github.com/dwimsey/openshift-pvmanager
Are you absolutely sure Perl is the right language for a car alarm remote, which has 4KB of Flash, 128 bytes of RAM and a 1MHz clock, and uses that for bit-banging a bidirectional radio, encryption, authentication, and power management by reducing the system clock to 4Hz when idle?
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
weighing in at 179kb, it's Hello World, the sequel http://www.pouet.net/prod.php?which=30244
beware he who denies you access to information for in his mind, he already deems himself to be your master (SMAC-ish)
You lucky, lucky bastard..
I had to learn on a computer with N O Memory, instead it had a rotating sawblade you had to etch your bits into, while moving!
FTS: She found that gcc was including libc even when you don't ask for it.
Shouldn't come as a surprise. C has a runtime, like most other languages. -- But really, this was a good article. Looking under the hood and finding the few things that are there is very instructive.
Looks like a counting fail or else you left out the $ to save space. :P. "Hello" and "World" are five bytes each, plus three bytes for the space, exclamation point, and dollar sign. 5 + 5 + 3 + 9 = 22 = 0x16, not 0x15, according to my math.
11k... that's really kind of apalling when I stop and think about it.
| LIB FEQUATES
| ORG $C100
|X FCC "hello world",$D,$A,$4
|ST LDX #X
| JSR PSTRNG
| JMP WARMS
| END ST
There's no question that a certain economy of implementation has been lost.
I've fallen off your lawn, and I can't get up.