I have a kind of off-topic NASM story. I think I was using it circa 2004 for a class, and was taking another class that required us to find 10 exploitable security holes in existing software. (This was DJB's "Unix Security Holes" class. Best class I ever took.) NASM was the first place I looked (my thought process was, it takes untrusted input and it's written in C), and indeed I found one: https://lists.debian.org/debian-security-announce/2005/msg00...
Incidentally, the other holes I found for that class were various XSS vulnerabilities in our course registration software. The administration was furious with me (I didn't exploit them, only proved that they existed), and banned me from using any computers at the University. DJB stuck up for me, though, and the vendor sent me a new iPod as a thank you. It was pretty stressful for a first-year student in 2004 though.
My parents really didn't want me being involved in any security-related fields, so I ended up not really touching it again. My take these days is that security is a subset of correctness; design for security, and make sure you implement it correctly, just like you do for any other feature. I also write a LOT of fuzz tests ;) But yeah, NASM was the beginning and end of my software security career, which I still find kind of amusing.
> just how thankless vulnerability research and computer security in general is
Thankless? Which world are you living in? Do you have any idea how much money skilled, even junior, security researches are able to earn from consulting? If you have skills, you can print money, and often while working from anywhere in the world.
Nice to see NASM is still going strong. I used this for a class I taught back in the 90's. The class supported both Windows and Linux (but most students used Windows) and NASM supported both and was free.
I ended up creating my own free online textbook for the course. It's sorta out of date now since it was for 32-bit processors.
Are you still working on the book?
After digging old stuffs from university days (more than 1 decade), I found the old unfinished Indonesian translation. Perhaps I can finish it.
Why would anybody use this over the assembler shipped with their compiler?
This might make sense if your project is written entirely in assembly, but does anybody even do that nowadays? For projects that are mostly in C/C++ with bits of assembly here and there, it's yet one more dependency your users have to install.
NASM has a logical and sane syntax that is both readable and maps directly to the generated instructions, in other words it is designed to be written by hand, not as an convenient intermediate format for the compiler to generate.
Contrast that to typical AT&T-syntax x86 assembly with bunch of meaningless punctuation and complex addressing modes represented by bunch of comma separated numbers. And with MASM that needs bunch of boilerplate and noise words, because the syntax is motivated by what was required to produce real-mode 16b object files.
If you write cross platform software, you might want MSVC on Windows and gcc on linux and their assemblers masm and gas have very different syntax. nasm outputs object files for both directly. Also the syntax in the context of especially macros is often a little better.
Trust me, at least on Intel, you do not want to write assembly inside your C/C++ code, unless it's just a couple of lines. The usual AT&T syntax will drive you nuts, and the additional syntax for embedding assembly only adds to the misery.
For any reasonable amounts (say, you want a function or several) of assembly, you want Intel syntax and standalone assembly files.
NASM is a great tool, although YASM should also be mentioned: https://yasm.tortall.net — YASM is what I used when I optimized an H.264 decoder for Intel-compatible CPUs way back in 2005 or so.
> The usual AT&T syntax will drive you nuts, and the additional syntax for embedding assembly only adds to the misery.
It's trivial to enable Intel syntax in inline assembly even under GCC. And if you're using Rust instead of C or C++ then the inline assembly syntax is actually really great and very pleasant to use.
And while that in itself is maybe not particularly exciting, I think the underlying point is more that assemblers like nasm allow for the implementation of toolchains like this, where you have some assembly with some C code. While not common, I'm sure cases like this are also not exceedingly rare.
nasm has better goto labels you can use sublabels within a block that don't need to be globally unique.
The data generation stuff is better aswell.
This was a while ago, and I could have missed these features else where, but that's why I ended up at nasm.
Yes, if youre just doing a bit of assembly, use whatever, but if you're doing a bigger project in assembly, nasm is optimised for that, rather than dealing with the output of a compiler.
We were taught NASM as part of a course and I'm so much accustomed to it's beautiful syntax.
Is it less capable than MASM? Don't have a reason to believe so because there's one to one correspondence between what you write and what's gets executed.
As Borland fanboy, TASM was already quite cool, the only thing I missed was MASM being more high level with its macro capabilities, but by time I got to play with MASM, I was already into Windows 3.x world.
I have been using NASM in my spare time recently because “learning” assembly is an itch I always had. I’m having so much fun. Cool to see it posted here.
I began learning computer programming with Logo [1], then BASIC, then C, Lisp, etc. However, somewhere along the way, growing dissatisfied with not knowing exactly what's going on under the hood, I began descending down the stack. That journey led me to learning about the CPU, using assemblers, as well as loading instructions in hexadecimal format into a memory by pushing buttons on a 8086 trainer kit. At one point, I also designed my own Mano Machine in VHDL which I then synthesised and tested on a Xilinx CPLD kit [2].
The last one was the most fun. It was very rewarding to see the abstract concepts presented in books come alive in the form of a working machine that could fetch, decode, and execute instructions from a memory. The memory was designed in VHDL too and implemented on the same Xilinx CPLD kit. Loading instructions into the memory required me to push DIP switches (one switch for each bit). A far cry from the comfort of Emacs running atop a modern operating system!
Those two adventures lied on opposite ends of a spectrum. There was the luxury of high level languages and tooling at one end. On the other end, there was the hands-on ritual of loading each bit of instruction, accomplished through the deliberate act of manipulating DIP switches. Such a laborious experience prompts a profound awareness that ultimately all software executes on physical matter.
Nestled in between these two extremes, there was a sweet spot involving assemblers. The first assembler I stumbled upon was the "A" command of DEBUG.EXE [2] of MS-DOS. The features were very minimalist and the tool was a bit more than an assembler. This humble debugger allowed me to peek into interrupt vector tables, inspect the content of ROM, learn how MS-DOS boots from scratch, etc. I later did come across GNU as, TASM, NASM, etc. which made me appreciate the number of bookkeeping problems a proper assembler solves. No more recalculating all the offsets for the jump and call instructions after every refactoring of the program!
These days, I work very high up in the stack where there are numerous layers of technology between what I type and what the physical machine executes. But I do fondly remember the days when armed with an assembler, some knowledge of the CPU and the computer architecture, we could plunge into the depths of the system, unravelling its intricacies to our heart's content.
I cannot remember the name of the 8086 trainer kit, unfortunately. That was more than 20 years ago. It indeed looked very much like the MCS-86 picture you have linked to. I could not have remembered the name of CPLD kit either if it weren't for the project report where I have kept a picture of the kit and its model name. It was Xilinx XC9572 PC84 CPLD Trainer.
TL;DR: I want to tinker with one assembler, which is better for tinkering, NASM or FASM?
I am looking to one day learn assembly (x86, x86-64 and potentially ARM) simply for tinkering hobby purposes, to prove I learned something watching all those Ben Eater TTL youtube videos and try my hand at logic design and creating toy programs that are as close to the metal as possible, just to say I can do it.
But part of the trick is not knowing where to start. There's MASM which appeals to me as a higher level language user in that you create those macros and use them in various places, and there's NASM and FASM which I like the idea of since they seem to be more portable to both Windows and Linux. I doubt I can write an assembly program and run it on an old android smartphone, so I'll leave that aside here.
Optimizations are enabled by the semantics of the language. If the language mandated that generated code must conform exactly to specific sequences of operations dictated by the source code, instead of merely respecting the observable behavior of the abstract machine, it would be impossible to optimize C code in the same way that it's impossible to optimize Assembly code.
> What actually makes C a high-level language isn't the language, but the optimizer passes in modern C compilers.
I don't think so because that would imply that a language would be low-level until someone writes an optimizing compiler for it. The "levelness" of a language shouldn't depend on implementation details.
I was thinking it might be feasible to tackle Advent of Code in assembler if you started out with a good set of macros and a library for handling common data structures and memory operations.
I personally would not be able to do that and keep up with the daily problems, but it might be fun.
You'd probably be better off with TCC or with GCC with -O0. Assembly can only outrun C when the programmer uses context-aware optimizations. If you're just using generic macros everywhere to piece together a solution you may as well just use a high-level language.
Oh, I wasn't thinking of optimized code. It just sounds kind of fun. And it would still probably still beat anything that doesn't target machine code. But yeah, the compiler is going to produce better code than I can in most cases.
TI has an Assembly language for DSPs that looks like C written in SSA form.
Macro Assemblers like MASM, TASM, NASM, YASM et al, provide directives to define structs, strings and such, alongside macros for most common control structures.
Incidentally, the other holes I found for that class were various XSS vulnerabilities in our course registration software. The administration was furious with me (I didn't exploit them, only proved that they existed), and banned me from using any computers at the University. DJB stuck up for me, though, and the vendor sent me a new iPod as a thank you. It was pretty stressful for a first-year student in 2004 though.
My parents really didn't want me being involved in any security-related fields, so I ended up not really touching it again. My take these days is that security is a subset of correctness; design for security, and make sure you implement it correctly, just like you do for any other feature. I also write a LOT of fuzz tests ;) But yeah, NASM was the beginning and end of my software security career, which I still find kind of amusing.