gPXE and dnsmasq do not get along, beware.
gPXE wants to find the boot filename in the dedicated slot in the reply packet. dnsmasq does something clever/stupid (I’m not sure which) and puts it someplace else. You have to use the --dhcp-no-override option to dnsmasq to make gPXE see the filename.
I don’t have proof, but I suspect this inflexibility in gPXE also makes it incompatible with the DHCP replies sent by qemu’s built-in DHCP server.
I have been killing myself debugging this, and I just wanted to share the answer here, since I didn’t read it elsewhere.
PS: This page gives a really good writeup of how to get non-fake network access for your qEmu machine.
Update: It looks like I had a bad version of gPXE. The latest (bien sur, released October 1st!) is much less frustrating to use.