[HN Gopher] Hello World
       ___________________________________________________________________
        
       Hello World
        
       Author : fbrusch
       Score  : 173 points
       Date   : 2024-04-08 09:07 UTC (13 hours ago)
        
 (HTM) web link (thecoder08.github.io)
 (TXT) w3m dump (thecoder08.github.io)
        
       | ben_w wrote:
       | I've been thinking recently, we might have too many layers of
       | abstraction in our systems.
       | 
       | And I didn't even know about most of the ones in this post.
        
         | mttpgn wrote:
         | Just because the number of abstraction layers can be reduced
         | doesn't mean they need to be. You might gain back some CPU
         | cycles, some milliseconds of execution time. But the tradeoffs
         | of maintainability, legibility, and developer quality-of-life
         | may, in the long run, reintroduce abstraction layers of some
         | other type back into the overall SDLC.
        
           | ben_w wrote:
           | > But the tradeoffs of maintainability, legibility, and
           | developer quality-of-life
           | 
           | Are in fact the things I think have become _worse_ from the
           | abstractions.
           | 
           | Well, the _recent_ abstractions. I like the ones that were
           | widespread until about 2018 or so.
        
             | richardwhiuk wrote:
             | None of the abstractions above are new in the last 5 years.
        
             | bitterblotter wrote:
             | Im curious. Can you expand / give examples?
        
         | nomel wrote:
         | > And I didn't even know about most of the ones in this post.
         | 
         | I think that's the answer to the question of "why do we have so
         | many". It's a great thing you don't have to know about them. Go
         | down a layer, and the people working there will think it's a
         | great thing they don't have to worry about the abstraction
         | below. Software development is, currently, a human task, so the
         | human needs necessarily structure it.
         | 
         | I can't comment on web development...
        
         | freeone3000 wrote:
         | Do some embedded work, even at the c-for-esp32 layer, and
         | you'll start to see the benefits of having an OS.
        
           | xandrius wrote:
           | Yep, it seems common for people who haven't actually
           | experienced something from the past to wish it was still like
           | then, not understanding why people decided the trade was
           | worth it.
           | 
           | You might save some bytes but boy how annoying and
           | complicated it can get.
        
           | ctrw wrote:
           | I can see the benefits of an os. I fail to see the benefits
           | of a browser pretending to be another os on top of the os.
        
       | MuffinFlavored wrote:
       | I got bored the other day and tried to achieve something similar
       | on MacOS with Rust:                   #![no_std]
       | #![no_main]                  use core::panic::PanicInfo;
       | #[panic_handler]         fn panic_handler(_panic: &PanicInfo<'_>)
       | -> ! {             // TODO: write panic message to stderr
       | write(2, "Panic occured\n".as_bytes()); // TODO: panic location +
       | message             unsafe { sc::syscall!(EXIT, 255 as u32) };
       | loop {}         }                  fn write(fd: usize, buf:
       | &[u8]) {             unsafe {                 sc::syscall!(WRITE,
       | fd, buf.as_ptr(), buf.len());             }         }
       | #[no_mangle]         pub extern "C" fn main() -> u32 {
       | write(1, "Hello, world!\n".as_bytes());             return 0;
       | }
       | 
       | Then I inspected the ELF output in Ghidra. No matter what it was
       | about ~16kb. I'm sure some code golf could be done to get it done
       | (which has obviously been done + written about + documented
       | before)
        
         | 082349872349872 wrote:
         | it's fun to golf, but how big are pages these days, anyway?
         | 
         | (and if you're using a language with a stack, your executable
         | probably ultimately loads as at least two pages: r/o and r/w)
        
           | anyfoo wrote:
           | 16kB on a Mac, so that was probably what they were running
           | into. You effectively can't make a program whose code
           | occupies less than 16kB.
        
         | speed_spread wrote:
         | Rust or not, 16kb is entirely satisfactory. I mean, it fits in
         | a Commodore 64's memory!
        
           | _the_inflator wrote:
           | Compared to a Hello World program on C64 written in assembler
           | probably not. ;)
           | 
           | I need roughly 24 bytes. 16kb means 16.384 bytes. I can think
           | of better usage of $4000 space in memory, FLI for example.
        
       | delta_p_delta_x wrote:
       | Sadly, like most 'hello world' deep dives, the author stops at
       | the `write` syscall and glosses over the rest. Everything before
       | the syscall essentially boils down to `printf` calling `puts`
       | calling `write`--it's one function call after another forwarding
       | the `char const*` through, with some book-keeping. In my opinion,
       | not the most interesting.
       | 
       | What comes _after_ the syscall is where everything gets very
       | interesting and very _very_ complicated. Of course, it also
       | becomes much harder to debug or reverse-engineer because things
       | get _very_ close to the hardware.
       | 
       | Here's a quick summary, roughly in order (I'm _still_ glossing
       | over; each of these steps probably has an entire battalion of
       | software and hardware engineers from tens of different companies
       | working on it, but I daresay it 's still more detailed than other
       | 'tours through 'hello world'):                 - The kernel
       | performs some setup setup to pipe the `stdout` of the hello world
       | process into some input (not necessarily `stdin`; could be a
       | function call too) of the terminal emulator process.        - The
       | terminal emulator calls into some typeface rendering library and
       | the GPU driver to set up a framebuffer for the new output.
       | - The above-mentioned typeface rendering library also interfaces
       | with the GPU driver to convert what was so far just a one-
       | dimensional byte buffer into a full-fledged two-dimensional
       | raster image:         - the corresponding font outlines for each
       | character byte is loaded from disk;         - each outline is
       | aligned into a viewport;          - these outlines are resized,
       | kerning and font metrics applied from the font files set by the
       | terminal emulator;         - the GPU rasterises and anti-aliases
       | the viewport (there are entire papers and textbooks written on
       | these two topics alone). Rasterisation of font outlines may be
       | done directly in hardware without shaders because nearly all
       | outlines are quadratic Bezier splines.       - This is a new
       | framebuffer for the terminal emulator's window, a 2D grid
       | containing (usually) RGB bytes.       - The windowing manager
       | takes this framebuffer result and *composits* with the window
       | frame (minimise/maximise/close buttons, window title, etc) and
       | the rest of the desktop--all this is done usually on the GPU as
       | well.         - If the terminal emulator window in question has
       | fancy transparency or 'frosted glass' effects, this composition
       | applies those effects with shaders here.       - The resultant
       | framebuffer is now at the full resolution and colour depth of the
       | monitor, which is then packetised into an HDMI or DisplayPort
       | signal by the GPU's display-out hardware, depending on which is
       | connected.       - This is converted into an electrical signal by
       | a DAC, and the result piped into the cable connecting the
       | monitor/internal display, at the frequency specified by the
       | monitor refresh rate.         - This is muddied by adaptive sync,
       | which has to signal the monitor for a refresh instead of blindly
       | pumping signals down the wire       - The monitor's input
       | hardware has an ADC which re-converts the electrical signal from
       | the cable into RGB bytes (or maybe not, and directly unwraps the
       | HDMI/DP packets for processing into the pixel-addressing signal,
       | I'm not a monitor hardware engineer).       - The electrical
       | signal representing the framebuffer is converted into signals for
       | the pixel-addressing hardware, which differs depending on the
       | exact display type--whether LCD, OLED, plasma, or even CRT. OLED
       | might be the most complicated since each *subpixel* needs to be
       | *individually* addressed--for a 3840 x 2400 WRGB OLED as seen on
       | LG OLED TVs, this is 3840 x 2400 x 4 = 36 864 000 subpixels, i.e.
       | nearly 37 million pixels.       - The display hardware refreshes
       | with the new signal (again, this refresh could be scan-line, like
       | CRT, or whole-framebuffer, like LCDs, OLEDs, and plasmas), and
       | you finally see the result.
       | 
       | Note that all this happens _at most_ within the frame time of a
       | monitor refresh, which is 16.67 ms for 60 Hz.
        
         | rossant wrote:
         | > The display hardware refreshes with the new signal (again,
         | this refresh could be scan-line, like CRT, or whole-
         | framebuffer, like LCDs, OLEDs, and plasmas), and you finally
         | see the result.
         | 
         | Nice explanation but you stopped at the human's visual system
         | which is where everything gets very interesting and very _very_
         | complicated. :)
         | 
         | [1] https://en.wikipedia.org/wiki/Visual_system
        
           | thedatamonger wrote:
           | thank you for that. I startled the dog with that laugh :)
        
         | wonnage wrote:
         | Most of this stuff is irrelevant to the program itself, e.g you
         | could've piped the output to /dev/null and none of this would
         | happen.
        
           | delta_p_delta_x wrote:
           | Fair enough.
           | 
           | However, the point of a hello world program is to introduce
           | programming to beginners, and make a computer _do something
           | one can visibly see_. I daresay this is made moot if you pipe
           | it into  /dev/null. I could then replace 'hello world' in the
           | title with 'any program _x_ that logs to `stdout` ', and it
           | wouldn't reach HN's front page.
           | 
           | In the same vein is this idea of 'a trip of abstractions'--I
           | don't know about you, but I always found most of them very
           | unsatisfying as they _always_ stop at the system call,
           | whether Linux or Windows. It really is afterwards where
           | things get interesting, you can 't deny that.
        
       | Syntaf wrote:
       | This reminds me of one of my favorite CS assignments in college
       | for a systems programming class:                   > Given a
       | hello world C++ snippet, submit the smallest possible compiled
       | binary
       | 
       | I remember using tools like readelf and objdump to inspect the
       | program and slowly rip away layers and compiler optimizations
       | until I ended up with the smallest possible binary that still
       | outputted "hello world". I googled around and of course found
       | someone who did it likely much better than any of us students
       | could have ever managed [1]
       | 
       | [1]:
       | https://www.muppetlabs.com/%7Ebreadbox/software/tiny/teensy....
        
         | eddd-ddde wrote:
         | Does it even matter that the snippet was c++? Couldn't you just
         | get the smallest binary that prints hello world and argue that
         | they are semantically equivalent?
         | 
         | That should be like 10 x86 instructions tops, plus the string
         | data.
        
           | Syntaf wrote:
           | Our curriculum was c++, so it was familiar territory for the
           | students in terms of both the language and the compiler but
           | yeah you can likely do this exercise with any compiled
           | language.
        
           | greenbandit wrote:
           | I don't think the smallest binary was the goal but rather the
           | smallest compiled binary. I assume they were restricted to a
           | specific compiler as well.
        
           | riazrizvi wrote:
           | Seems like it would miss the point of the exercise, which was
           | to learn what a C++ compiler puts into an executable. Though
           | I do realize that if there was a magic wand to get a grade
           | without doing the work, some of us would take it.
        
       | Retr0id wrote:
       | > All modern big and important programs that make a computer work
       | are written this way [AoT-compiled to native code].
       | 
       | This is the conventional wisdom, but it's increasingly not true.
        
       | bkallus wrote:
       | This almost entirely skips the role of the dynamic linker, which
       | is arguably the true entry point of the program.
       | 
       | If you are interested in that argument, see
       | https://gist.github.com/kenballus/c7eff5db56aa8e4810d39021b2....
        
       | norir wrote:
       | > I'm sorry the ending maybe wasn't as satisfying as you hoped.
       | I'm happy someone found this interesting. I'm not quite sure why
       | I wrote this, but it's now after midnight so I should get some
       | sleep.
       | 
       | This was actually a perfect ending to this piece.
        
       | cancerhacker wrote:
       | I liked and appreciated this, two points I'd like to make: you
       | should disable optimizations and whatever inlining caused printf
       | to become puts (or, alternatively, write the hello world to use
       | puts directly), second would be to break your compile step into
       | the 4 real parts: preprocess, compile, assemble, link. Or add
       | --save-temps to the cc line and describe the various files
       | created. There's a lot less magic involved if you can see the
       | pipeline.
        
       | sohzm wrote:
       | This reminded me of this video "Advanced Hello World in Zig -
       | Loris Cro" https://youtu.be/iZFXAN8kpPo although not a equivalent
       | comparison but still a intresting watch
        
       | Bengalilol wrote:
       | Just saying hi ! (and thanks for the read, got me back to the old
       | days of ASM One and SEKA on Amiga, trying to clean up my memory
       | dust pile)
        
       | ctrw wrote:
       | > So, modern software systems on today's hardware are so complex
       | and intricate that it really makes no sense to try and fully
       | understand one little thing that your computer did
       | 
       | I was going to say that this looks like the type of dumb shit I
       | said in undergrad while learning comouter basics.
       | 
       | Then I saw the OP is 16. Continue being a dumb ass OP, no one was
       | born knowing and being confidently wrong is the fastest way to
       | grow.
        
         | forrestthewoods wrote:
         | Strangely harsh comment.
         | 
         | I mean it's impossible for anyone to "fully understand". This
         | post didn't even get to the hardware level!
         | 
         | This ancient Google+ post is one of my all time-favorites:
         | Dizzying but Invisible Depth.
         | https://archive.is/100Wn#selection-693.0-693.28
         | 
         | I do think it's critical for programmers to be curious and dig
         | a few levels deep. This young programmer went about 7 levels
         | deeper than almost anyone would. Kudos to him!
        
       | stevefolta wrote:
       | > Unlike python, however, you can't just call an interpreter to
       | run this program.
       | 
       | Sure you can: "tcc -run hello.c". Okay, technically that's an in-
       | memory compiler rather than an interpreter.
       | 
       | For extra geek points, have your program say "Hellorld" instead
       | of "Hello world".
        
       | qznc wrote:
       | Another interesting fact: Write a Hello World program in C++, run
       | the preprocessor on it (g++ -E), then count the lines of the
       | output.
       | 
       | I just tried and it shows me 33738 lines (744 lines for C btw).
       | 
       | In a language like C++, even Hello World uses like half of all
       | the language features.
        
         | ColonelPhantom wrote:
         | Arguably, most of that is probably dead code included from
         | <iostream>. Most of it is likely never called for a simple
         | Hello World.
         | 
         | Similarly, in C, you can just give the definition of printf and
         | omit the include of stdio.h, which also saves a ton of
         | preprocessed lines.
        
         | nsguy wrote:
         | Don't include the standard headers and just put it the
         | definition for the symbols you're using. With std::cout you
         | might end up pulling your hair out to find everything but I
         | can't imagine it'd be more than a few dozen lines... Not gonna
         | try ;)
         | 
         | With C you just need a definition for printf instead of
         | including stdio. In the old days you'd get by without even
         | defining it at all.
        
       ___________________________________________________________________
       (page generated 2024-04-08 23:00 UTC)