Basically, you just have to add a test in the data step to see if it's the first observation for the city, and output an extra text (city label) at a higher position, in addition to the regular text.
data users;
length city name $50;
statecode='NC'; city='Cary'; name='Robert'; output;
statecode='NC'; city='Cary'; name='Ed'; output;
statecode='NC'; city='Asheville'; name='Bill'; output;
run;
proc sql;
create table users as
select users.*, uscity.x, uscity.y
from users left join maps.uscity
on (users.statecode=uscity.statecode) and (users.city=uscity.city);
quit; run;
proc sort data=users out=users;
by statecode city;
run;
data users; set users;
by statecode city;
if first.city then count=0;
count+1;
run;
data anno_users; set users;
length style $50;
xsys='2'; ysys='2'; position='b'; when='a';
function='label'; color='black';
if count=1 then do;
style='albany amt/bold';
position='2';
text=trim(left(city));
output;
end;
y=y-((count-1)*.013);
style='albany amt';
position='5';
text=trim(left(name));
output;
run;
pattern value=solid color=white;
proc gmap data=maps.us map=maps.us anno=anno_users;
id state;
choro state / levels=1 coutline=gray;
run;