I read somewhere that C is preferred for drivers and firmware on embedded systems because it requires less run-time support. I could not understand the part 'run-time support'. My understanding is C code is converted to assembly code, which is flashed on a embedded device in form of a binary file. Please correct me, if this is wrong. If it is correct, what kind of run-time support is required by C in this scenario?
In some cases, for any programming language, you run across things that are important to do but not easy for a developer to express in a good way in that language. They frequently tend to be very low-level tasks that are very common, and often things whose implementation will vary from one platform to another even though the basic nature of what needs to be done remains pretty constant.
Language designers put things like this in as "magic" that's already available as a prebuilt library for the developer to use, so they don't have to design it themselves. This is known as a runtime library.
Because C is a very low-level language with a small feature set, it has a small runtime, but it still needs runtime support for things like I/O (works differently on every platform) and memory management (it's technically not possible to write a standards-conforming
malloc in C).
Many higher-level languages include more complex features that require more runtime support, or simply include more things in the standard runtime libraries to provide a richer, more unified developer experience.
What is run-time support required by a language?
Let's look broadly at some of the features that involve various levels of runtime support.
Memory management in many languages involves language functions like
new, and garbage collection. Garbage collection requires tracing objects to identify live vs. dead entities. This typically requires runtime support involving scanning of stacks and heap objects.
By contrast, in C, memory management is manual and consists of malloc & free, which are library routines you could write yourself in terms of an operating system call to obtain a heap (though as @Mason writes, perhaps not standards compliant).
Error handling & recovery
In many languages, error handling is accomplished via exceptions. Throwing, (stack unwinding,) and catching, in particular, require runtime support, involving coordination between the compiler and the runtime stack.
By contrast, error handling in C is explicit; stack unwinding is supported by a library calls, albeit specialized routines, such as longjmp, rather than the more complex exception handling.
Dynamic Type Handling
Loading and unloading classes, lazy loading classes, class initialization generally require some runtime support. Casting, e.g. down-casting or interface casting generally require some runtime support. Reflection & serialization, also generally require some runtime support. The runtime tracks fields of and layout of loaded classes.
By contrast, C does not provide dynamic class loading: dynamic library loading may be supported by operating system calls without significant runtime support from the C language, and, C does not have runtime casts, or reflection or serialization features. Fields are assigned offsets at compile time; the complete size of structures is known at compile time, so runtime support is not required.
Most languages provide for floating point data types; some provide decimal types in the language, and others provide overflow and underflow checking (usually coordinated with the languages exception handling mechanisms).
C supports floating point operations; sometimes these are supported by operating system emulations of floating point hardware, other times by low-level language libraries known to the compiler.
For C other operations are provided by more ordinary library routines (that don't necessarily require compiler modification to provide) rather than built in language features.