When does system generate global variable $user?
Drupal initializes the global $user during bootstrap. Unfortunately, it doesn't invoke any hook, as modules are not yet loaded. (Loading the enabled modules is the last step of Drupal bootstrap.)

The following code is used in the Drupal session handler _drupal_session_read().

  // Handle the case of first time visitors and clients that don't store
  // cookies (eg. web crawlers).
  $insecure_session_name = substr(session_name(), 1);
  if (!isset($_COOKIE[session_name()]) &amp;&amp; !isset($_COOKIE[$insecure_session_name])) {
    $user = drupal_anonymous_user();
    return '';
  }

  // Otherwise, if the session is still active, we have a record of the
  // client's session in the database. If it's HTTPS then we are either have
  // a HTTPS session or we are about to log in so we check the sessions table
  // for an anonymous session with the non-HTTPS-only cookie.
  if ($is_https) {
    $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' =&gt; $sid))-&gt;fetchObject();
    if (!$user) {
      if (isset($_COOKIE[$insecure_session_name])) {
        $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array(
          ':sid' =&gt; $_COOKIE[$insecure_session_name],
        ))
        -&gt;fetchObject();
      }
    }
  }
  else {
    $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' =&gt; $sid))-&gt;fetchObject();
  }


To extend the global $user, you can implement hook_boot(), which is invoked when Drupal is still bootstrapping, or hook_init(), which is not invoked for cached pages. hook_user_load() is invoked when user_load() is called, but user_load() is not used for the global $user.  

As side note, the global $user is not a complete user object. It contains the data saved in the "users" table, and not (for example) the value of any field (fields implemented from the field API) associated to the user entity.
$user-&gt;data can be used to store extra data for the user object. Its content can be altered through hook_user_presave() in the same way done by overlay_user_presave().

function overlay_user_presave(&amp;$edit, $account, $category) {
  if (isset($edit['overlay'])) {
    $edit['data']['overlay'] = $edit['overlay'];
  }
}