After several days research, I found that in Ubuntu /etc/gdm/Xsession is executed instead of /etc/X11/Xsession. Though both run the scripts under /etc/X11/Xsession.d.
I have defined /etc/X11/Xmodmap and created a hook script in /etc/X11/Xsession.d/40load-xmodmap, but the loaded xmodmap is lost after 99x11-common_start.
Debug codes:
/etc/X11/Xseesion:
...
for file in Xsession.d/*; do
. $file
echo The current xmodmap is:
xmodmap
done
...
The printed xmodmap shows 40load-xmodmap works very well, but the defined key mods are lost after the desktop is brought up.
At last, I defined xmodmap in user directory ~/.Xmodmap, this time when the session is started a popup window prompts me to enable the Xmodmap. So I guess maybe GNOME desktop reset the xmodmap?