Assembly language is seldom needed except in imbedded applications
Even in embedded systems, assembler is now rarely used. I'm working for a company developing embedded systems since 2015, and we haven't written a single line of assembler during that time. I know that some very old projects had a few lines of assembler, back when the company started 25 years ago, when 8051 was state of the art. AVR and ARM processors are generally programmed in C, or at least we do so. On larger ARM processors, C++ is also used. For us, the border line is the user interface. Code written for bare metal is written in C, code written to run on (embedded) Linux is written in C++, Code written for Windows is written in C#.
Why?
1 - Modern C compilers generate highly optimized assembler code. It is very hard to manually produce that code quality. Granted, it is sometimes hard to read, especially when compiled with -O2 or -O3, but you rarely have to read it.
2 - C code can be reused. To name just a trivial example: Our system clock and software timer library was written years before I was hired, when AVR processors were state of the art. It was written in C. Porting it to ARM processors required just recompiling it. Making it run on 80x86, Z80, 6502 or 68000 will also require just recompiling it. It does not contain any processor-specific or machine-specific code. You need a little piece of code that will be called from a hardware interrupt, but that's in a driver for the library, and generally needs less than 100 lines of code. If that software timer library had been written in assembler, we would have to rewrite it from scratch for every new processor family.
3 - The vendor-supplied interface to the microcontroller is now C. You get a C/C++ toolchain (often GCC) and a ton of C headers that describe the entire controller. Hardware register access is either memory mapped (ARM) or well hidden behind C preprocessor macros (AVR). If you wish, you can still write assembler code, but you generally don't.
4 - You don't have to learn machine-specific assembler code. It is good to have an idea of what the processor can do easily (adding 8 bit integers) and what is hard (e.g. floats, integer division, misaligned memory access), but you generally write C, no matter what processor you are using.
5 - Debugging at C source code level is standard. You really have to confuse processor and debugger to make it fall back to a disassembly listing. In other words: When C source code level debugging does not work any more, something has gone horrible wrong, and assembler knowledge won't get you out of that situation.
6 - When running on top of Linux, Windows, or any other (general purpose) operating system, writing assembler code does not make any sense. If your code runs too slow, you need a real-time OS and/or a faster machine and/or a different approach to the basic problem. Assembler will rarely help you.
A note on the different approach: We often split the problem into a real-time task running on bare metal on a sufficiently fast microcontroller and a user interface task running on a general-purpose OS. That way, the microcontoller can do its job as efficient as possible, and only needs to look at the input from the user interface every few milliseconds. All of the fancy eye candy happens on the general purpose OS, burning tons of CPU cycles, without disturbing the real-time task. Every few seconds, when some user hits the touch screen, an event is generated, transformed, and ends as a short message in a buffer of the microcontroller. Or something interesting happens on the real-time side, a short message is send through the general-purpose OS into the user interface task, and makes the screen draw craploads of animations.
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)