What are the differences between rand() function and RNG (Random number generator) peripheral?
Dave's answer quite nicely resume it, but to clarify a little bit more on the second option:

a real hardware random number generator uses a physical entropy source.  Such an entropy source could be cosmic radiation, electrical noise, avanlanche effect from a reverse-biased diode (or BJT transistor), chua circuit, etc.  The less deterministic the entropy source, the better the quality of the random output.  An ideal entropy source would be to use a quantum physics effect, or something that cannot possibly modeled with deterministic equations.

Another important factor with random number generators is that the entropy source may generate only a limited amount of entropy per unit of time.  A good example is the chua circuit: while it is quite random, it has very poor speed and cannot possibly be used for real-life application.

In many processor/microcontrollers with built-in RNGs, the clock drift from 2 to 4 clocks which are deliberatly incorrectly synchronized is used.  Then, they use both analog and digital filters to randomize even more the pattern and shift-in the result in a register.  Performing such filtering requires a few cycles, which explains the minimum amount of cycles required on a given clock before the newer value is available.

The clock drifting is not quite a quantum effect, so it could be modeled, but it is random enough, because it is dependent on a lot of parameters, such as temperature, silicon process, frequency of operation, electrical noise, background radiations, etc.

In applications where the hardware RNG do not have sufficient throughtput (such as in highly demanding cryptographic applications), it is quite common to use the hardware RNG as a seed for a pseudo random number generator such as the rand() function in the sdtlib.  However, such application usually provide a better implementation of rand() which is specifically design to run from a seed which may be discarded very often with true random values.  In newer Intel processor with integrated hardware RNGs, the pseudo-random algorithm part is directly integrated in the silicon, so it is performed by hardware, yielding very high random throughtput.

If you mind about the rand() method itself, it is only a methematical expression which is designed to generate a large enough amount of entropy.  Large enough being dependant on the application: for cryptographic keys generations, the randomness is required to be of higher quality that the randomness required for a simple random shuffle in your favorite music player.  It is obvious that the higher the quality of the random output, the higher the computational cost of the random number.

The operations involved in a random number are quite similar to the one involved in computing the MD5 hash of a file: they try to use a kind of bit avalanche effect so that a single bit change in a seed value changes the whole generating pattern.  As a side note, I do NOT recommand using MD5 as a pseudo-random number generator; it was only an example.  It would be both inefficient and not so random, but the point is there: if you feed the same file to an MD5 hasing algorithm, you will always get the same deterministic output, pretty much the same way you would always get the same output from the rand() function if you input the same seed unless your implementation depends on some arbitrary elements such as current time.