Merge branch 'net80211-update' of git://leaf.dragonflybsd.org/~rpaulo/dragonfly into...
[dragonfly.git] / sys / platform / pc32 / i386 / support.s
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/i386/i386/support.s,v 1.67.2.5 2001/08/15 01:23:50 peter Exp $
34  * $DragonFly: src/sys/platform/pc32/i386/support.s,v 1.21 2008/05/08 01:21:04 dillon Exp $
35  */
36
37 #include "use_npx.h"
38
39 #include <machine/asmacros.h>
40 #include <machine/cputypes.h>
41 #include <machine/pmap.h>
42 #include <machine/specialreg.h>
43
44 #include "assym.s"
45
46 #define IDXSHIFT        10
47
48         .data
49
50         .globl  memcpy_vector
51 memcpy_vector:
52         .long   asm_generic_memcpy
53
54         .globl  bcopy_vector
55 bcopy_vector:
56         .long   asm_generic_bcopy
57
58         .globl  ovbcopy_vector
59 ovbcopy_vector:
60         .long   asm_generic_bcopy
61
62         .text
63
64 /* fillw(pat, base, cnt) */
65 ENTRY(fillw)
66         pushl   %edi
67         movl    8(%esp),%eax
68         movl    12(%esp),%edi
69         movl    16(%esp),%ecx
70         cld
71         rep
72         stosw
73         popl    %edi
74         ret
75
76 /*
77  * void bcopy(const void *s, void *d, size_t count)
78  *
79  * Normal bcopy() vector, an optimized bcopy may be installed in
80  * bcopy_vector.
81  */
82 ENTRY(bcopy)
83         pushl   %esi
84         pushl   %edi
85         movl    4+8(%esp),%esi                  /* caddr_t from */
86         movl    8+8(%esp),%edi                  /* caddr_t to */
87         movl    12+8(%esp),%ecx                 /* size_t  len */
88         call    *bcopy_vector
89         popl    %edi
90         popl    %esi
91         ret
92
93 /*
94  * Generic (integer-only) bcopy() vector.
95  */
96 ENTRY(generic_bcopy)
97         pushl   %esi
98         pushl   %edi
99         movl    4+8(%esp),%esi                  /* caddr_t from */
100         movl    8+8(%esp),%edi                  /* caddr_t to */
101         movl    12+8(%esp),%ecx                 /* size_t  len */
102         call    asm_generic_bcopy
103         popl    %edi
104         popl    %esi
105         ret
106
107 ENTRY(ovbcopy)
108         pushl   %esi
109         pushl   %edi
110         movl    4+8(%esp),%esi                  /* caddr_t from */
111         movl    8+8(%esp),%edi                  /* caddr_t to */
112         movl    12+8(%esp),%ecx                 /* size_t  len */
113         call    *ovbcopy_vector
114         popl    %edi
115         popl    %esi
116         ret
117
118 /*
119  * void *memcpy(void *d, const void *s, size_t count)
120  *
121  * Note: memcpy does not have to support overlapping copies.
122  *
123  * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
124  * while bcopy() returns void.
125  */
126 ENTRY(memcpy)
127         pushl   %esi
128         pushl   %edi
129         movl    4+8(%esp),%edi
130         movl    8+8(%esp),%esi
131         movl    12+8(%esp),%ecx
132         call    *memcpy_vector
133         movl    4+8(%esp),%eax
134         popl    %edi
135         popl    %esi
136         ret
137
138 /*
139  * A stack-based on-fault routine is used for more complex PCB_ONFAULT
140  * situations (such as memcpy/bcopy/bzero).  In this case the on-fault
141  * routine must be pushed on the stack.
142  */
143 stack_onfault:
144         ret
145
146 /*****************************************************************************/
147 /* copyout and fubyte family                                                 */
148 /*****************************************************************************/
149 /*
150  * Access user memory from inside the kernel. These routines and possibly
151  * the math- and DOS emulators should be the only places that do this.
152  *
153  * We have to access the memory with user's permissions, so use a segment
154  * selector with RPL 3. For writes to user space we have to additionally
155  * check the PTE for write permission, because the 386 does not check
156  * write permissions when we are executing with EPL 0. The 486 does check
157  * this if the WP bit is set in CR0, so we can use a simpler version here.
158  *
159  * These routines set curpcb->onfault for the time they execute. When a
160  * protection violation occurs inside the functions, the trap handler
161  * returns to *curpcb->onfault instead of the function.
162  */
163
164 /*
165  * copyout(from_kernel, to_user, len)  - MP SAFE
166  */
167 ENTRY(copyout)
168         movl    PCPU(curthread),%eax
169         movl    TD_PCB(%eax),%eax
170         pushl   %esi
171         pushl   %edi
172         pushl   %ebx
173         pushl   $copyout_fault2
174         movl    $stack_onfault,PCB_ONFAULT(%eax)
175         movl    4+16(%esp),%esi
176         movl    8+16(%esp),%edi
177         movl    12+16(%esp),%ebx
178         testl   %ebx,%ebx                       /* anything to do? */
179         jz      done_copyout
180
181         /*
182          * Check explicitly for non-user addresses.  If 486 write protection
183          * is being used, this check is essential because we are in kernel
184          * mode so the h/w does not provide any protection against writing
185          * kernel addresses.
186          */
187
188         /*
189          * First, prevent address wrapping.
190          */
191         movl    %edi,%eax
192         addl    %ebx,%eax
193         jc      copyout_fault1
194 /*
195  * XXX STOP USING VM_MAX_USER_ADDRESS.
196  * It is an end address, not a max, so every time it is used correctly it
197  * looks like there is an off by one error, and of course it caused an off
198  * by one error in several places.
199  */
200         cmpl    $VM_MAX_USER_ADDRESS,%eax
201         ja      copyout_fault1
202
203         /*
204          * Convert copyout to memcpy_vector(dest:%edi, src:%esi, count:%ecx)
205          */
206         movl    %ebx,%ecx
207         call    *memcpy_vector
208
209 done_copyout:
210         /*
211          * non-error return
212          */
213         addl    $4,%esp
214         movl    PCPU(curthread),%edx
215         xorl    %eax,%eax
216         movl    TD_PCB(%edx),%edx
217         popl    %ebx
218         popl    %edi
219         popl    %esi
220         movl    %eax,PCB_ONFAULT(%edx)
221         ret
222
223         ALIGN_TEXT
224 copyout_fault1:
225         addl    $4,%esp         /* skip pushed copyout_fault vector */
226 copyout_fault2:
227         popl    %ebx
228         popl    %edi
229         popl    %esi
230         movl    PCPU(curthread),%edx
231         movl    TD_PCB(%edx),%edx
232         movl    $0,PCB_ONFAULT(%edx)
233         movl    $EFAULT,%eax
234         ret
235
236 /*
237  * copyin(from_user, to_kernel, len) - MP SAFE
238  */
239
240 ENTRY(copyin)
241         movl    PCPU(curthread),%eax
242         movl    TD_PCB(%eax),%eax
243         pushl   %esi
244         pushl   %edi
245         pushl   $copyin_fault2
246         movl    $stack_onfault,PCB_ONFAULT(%eax)
247         movl    4+12(%esp),%esi                 /* caddr_t from */
248         movl    8+12(%esp),%edi                 /* caddr_t to */
249         movl    12+12(%esp),%ecx                /* size_t  len */
250
251         /*
252          * make sure address is valid
253          */
254         movl    %esi,%edx
255         addl    %ecx,%edx
256         jc      copyin_fault1
257         cmpl    $VM_MAX_USER_ADDRESS,%edx
258         ja      copyin_fault1
259
260         /*
261          * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
262          */
263         call    *memcpy_vector
264
265         /*
266          * return 0 (no error)
267          */
268         addl    $4,%esp
269         movl    PCPU(curthread),%edx
270         xorl    %eax,%eax
271         movl    TD_PCB(%edx),%edx
272         popl    %edi
273         popl    %esi
274         movl    %eax,PCB_ONFAULT(%edx)
275         ret
276
277         /*
278          * return EFAULT
279          */
280         ALIGN_TEXT
281 copyin_fault1:
282         addl    $4,%esp         /* skip pushed copyin_fault vector */
283 copyin_fault2:
284         popl    %edi
285         popl    %esi
286         movl    PCPU(curthread),%edx
287         movl    TD_PCB(%edx),%edx
288         movl    $0,PCB_ONFAULT(%edx)
289         movl    $EFAULT,%eax
290         ret
291
292 /*
293  * casuword.  Compare and set user word.  Returns -1 or the current value.
294  */
295
296 ENTRY(casuword)
297         movl    PCPU(curthread),%ecx
298         movl    TD_PCB(%ecx),%ecx
299         movl    $fusufault,PCB_ONFAULT(%ecx)
300         movl    4(%esp),%edx                    /* dst */
301         movl    8(%esp),%eax                    /* old */
302         movl    12(%esp),%ecx                   /* new */
303
304         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address is valid */
305         ja      fusufault
306
307 #ifdef SMP
308         lock
309 #endif
310         cmpxchgl %ecx,(%edx)                    /* Compare and set. */
311
312         /*
313          * The old value is in %eax.  If the store succeeded it will be the
314          * value we expected (old) from before the store, otherwise it will
315          * be the current value.
316          */
317
318         movl    PCPU(curthread),%ecx
319         movl    TD_PCB(%ecx),%ecx
320         movl    $fusufault,PCB_ONFAULT(%ecx)
321         movl    $0,PCB_ONFAULT(%ecx)
322         ret
323 END(casuword)
324
325 /*
326  * fu{byte,sword,word} - MP SAFE
327  *
328  *      Fetch a byte (sword, word) from user memory
329  */
330 ENTRY(fuword)
331         movl    PCPU(curthread),%ecx
332         movl    TD_PCB(%ecx),%ecx
333         movl    $fusufault,PCB_ONFAULT(%ecx)
334         movl    4(%esp),%edx                    /* from */
335
336         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address is valid */
337         ja      fusufault
338
339         movl    (%edx),%eax
340         movl    $0,PCB_ONFAULT(%ecx)
341         ret
342
343 /*
344  * fusword - MP SAFE
345  */
346 ENTRY(fusword)
347         movl    PCPU(curthread),%ecx
348         movl    TD_PCB(%ecx),%ecx
349         movl    $fusufault,PCB_ONFAULT(%ecx)
350         movl    4(%esp),%edx
351
352         cmpl    $VM_MAX_USER_ADDRESS-2,%edx
353         ja      fusufault
354
355         movzwl  (%edx),%eax
356         movl    $0,PCB_ONFAULT(%ecx)
357         ret
358
359 /*
360  * fubyte - MP SAFE
361  */
362 ENTRY(fubyte)
363         movl    PCPU(curthread),%ecx
364         movl    TD_PCB(%ecx),%ecx
365         movl    $fusufault,PCB_ONFAULT(%ecx)
366         movl    4(%esp),%edx
367
368         cmpl    $VM_MAX_USER_ADDRESS-1,%edx
369         ja      fusufault
370
371         movzbl  (%edx),%eax
372         movl    $0,PCB_ONFAULT(%ecx)
373         ret
374
375         ALIGN_TEXT
376 fusufault:
377         movl    PCPU(curthread),%ecx
378         movl    TD_PCB(%ecx),%ecx
379         xorl    %eax,%eax
380         movl    %eax,PCB_ONFAULT(%ecx)
381         decl    %eax
382         ret
383
384 /*
385  * su{byte,sword,word} - MP SAFE
386  *
387  *      Write a byte (word, longword) to user memory
388  */
389 ENTRY(suword)
390         movl    PCPU(curthread),%ecx
391         movl    TD_PCB(%ecx),%ecx
392         movl    $fusufault,PCB_ONFAULT(%ecx)
393         movl    4(%esp),%edx
394
395         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address validity */
396         ja      fusufault
397
398         movl    8(%esp),%eax
399         movl    %eax,(%edx)
400         xorl    %eax,%eax
401         movl    PCPU(curthread),%ecx
402         movl    TD_PCB(%ecx),%ecx
403         movl    %eax,PCB_ONFAULT(%ecx)
404         ret
405
406 /*
407  * susword - MP SAFE
408  */
409 ENTRY(susword)
410         movl    PCPU(curthread),%ecx
411         movl    TD_PCB(%ecx),%ecx
412         movl    $fusufault,PCB_ONFAULT(%ecx)
413         movl    4(%esp),%edx
414
415         cmpl    $VM_MAX_USER_ADDRESS-2,%edx     /* verify address validity */
416         ja      fusufault
417
418         movw    8(%esp),%ax
419         movw    %ax,(%edx)
420         xorl    %eax,%eax
421         movl    PCPU(curthread),%ecx                    /* restore trashed register */
422         movl    TD_PCB(%ecx),%ecx
423         movl    %eax,PCB_ONFAULT(%ecx)
424         ret
425
426 /*
427  * subyte - MP SAFE
428  */
429 ENTRY(subyte)
430         movl    PCPU(curthread),%ecx
431         movl    TD_PCB(%ecx),%ecx
432         movl    $fusufault,PCB_ONFAULT(%ecx)
433         movl    4(%esp),%edx
434
435         cmpl    $VM_MAX_USER_ADDRESS-1,%edx     /* verify address validity */
436         ja      fusufault
437
438         movb    8(%esp),%al
439         movb    %al,(%edx)
440         xorl    %eax,%eax
441         movl    PCPU(curthread),%ecx            /* restore trashed register */
442         movl    TD_PCB(%ecx),%ecx
443         movl    %eax,PCB_ONFAULT(%ecx)
444         ret
445
446 /*
447  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
448  *
449  *      copy a string from from to to, stop when a 0 character is reached.
450  *      return ENAMETOOLONG if string is longer than maxlen, and
451  *      EFAULT on protection violations. If lencopied is non-zero,
452  *      return the actual length in *lencopied.
453  */
454 ENTRY(copyinstr)
455         pushl   %esi
456         pushl   %edi
457         movl    PCPU(curthread),%ecx
458         movl    TD_PCB(%ecx),%ecx
459         movl    $cpystrflt,PCB_ONFAULT(%ecx)
460
461         movl    12(%esp),%esi                   /* %esi = from */
462         movl    16(%esp),%edi                   /* %edi = to */
463         movl    20(%esp),%edx                   /* %edx = maxlen */
464
465         movl    $VM_MAX_USER_ADDRESS,%eax
466
467         /* make sure 'from' is within bounds */
468         subl    %esi,%eax
469         jbe     cpystrflt
470
471         /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
472         cmpl    %edx,%eax
473         jae     1f
474         movl    %eax,%edx
475         movl    %eax,20(%esp)
476 1:
477         incl    %edx
478         cld
479
480 2:
481         decl    %edx
482         jz      3f
483
484         lodsb
485         stosb
486         orb     %al,%al
487         jnz     2b
488
489         /* Success -- 0 byte reached */
490         decl    %edx
491         xorl    %eax,%eax
492         jmp     cpystrflt_x
493 3:
494         /* edx is zero - return ENAMETOOLONG or EFAULT */
495         cmpl    $VM_MAX_USER_ADDRESS,%esi
496         jae     cpystrflt
497 4:
498         movl    $ENAMETOOLONG,%eax
499         jmp     cpystrflt_x
500
501 cpystrflt:
502         movl    $EFAULT,%eax
503
504 cpystrflt_x:
505         /* set *lencopied and return %eax */
506         movl    PCPU(curthread),%ecx
507         movl    TD_PCB(%ecx),%ecx
508         movl    $0,PCB_ONFAULT(%ecx)
509         movl    20(%esp),%ecx
510         subl    %edx,%ecx
511         movl    24(%esp),%edx
512         testl   %edx,%edx
513         jz      1f
514         movl    %ecx,(%edx)
515 1:
516         popl    %edi
517         popl    %esi
518         ret
519
520
521 /*
522  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
523  */
524 ENTRY(copystr)
525         pushl   %esi
526         pushl   %edi
527
528         movl    12(%esp),%esi                   /* %esi = from */
529         movl    16(%esp),%edi                   /* %edi = to */
530         movl    20(%esp),%edx                   /* %edx = maxlen */
531         incl    %edx
532         cld
533 1:
534         decl    %edx
535         jz      4f
536         lodsb
537         stosb
538         orb     %al,%al
539         jnz     1b
540
541         /* Success -- 0 byte reached */
542         decl    %edx
543         xorl    %eax,%eax
544         jmp     6f
545 4:
546         /* edx is zero -- return ENAMETOOLONG */
547         movl    $ENAMETOOLONG,%eax
548
549 6:
550         /* set *lencopied and return %eax */
551         movl    20(%esp),%ecx
552         subl    %edx,%ecx
553         movl    24(%esp),%edx
554         testl   %edx,%edx
555         jz      7f
556         movl    %ecx,(%edx)
557 7:
558         popl    %edi
559         popl    %esi
560         ret
561
562 ENTRY(bcmp)
563         pushl   %edi
564         pushl   %esi
565         movl    12(%esp),%edi
566         movl    16(%esp),%esi
567         movl    20(%esp),%edx
568         xorl    %eax,%eax
569
570         movl    %edx,%ecx
571         shrl    $2,%ecx
572         cld                                     /* compare forwards */
573         repe
574         cmpsl
575         jne     1f
576
577         movl    %edx,%ecx
578         andl    $3,%ecx
579         repe
580         cmpsb
581         je      2f
582 1:
583         incl    %eax
584 2:
585         popl    %esi
586         popl    %edi
587         ret
588
589
590 /*
591  * Handling of special 386 registers and descriptor tables etc
592  */
593 /* void lgdt(struct region_descriptor *rdp); */
594 ENTRY(lgdt)
595         /* reload the descriptor table */
596         movl    4(%esp),%eax
597         lgdt    (%eax)
598
599         /* flush the prefetch q */
600         jmp     1f
601         nop
602 1:
603         /* reload "stale" selectors */
604         movl    $KDSEL,%eax
605         mov     %ax,%ds
606         mov     %ax,%es
607         mov     %ax,%gs
608         mov     %ax,%ss
609         movl    $KPSEL,%eax
610         mov     %ax,%fs
611         mov     %ax,%gs
612
613         /* reload code selector by turning return into intersegmental return */
614         movl    (%esp),%eax
615         pushl   %eax
616         movl    $KCSEL,4(%esp)
617         lret
618
619 /*
620  * void lidt(struct region_descriptor *rdp);
621  */
622 ENTRY(lidt)
623         movl    4(%esp),%eax
624         lidt    (%eax)
625         ret
626
627 /*
628  * void lldt(u_short sel)
629  */
630 ENTRY(lldt)
631         lldt    4(%esp)
632         ret
633
634 /*
635  * void ltr(u_short sel)
636  */
637 ENTRY(ltr)
638         ltr     4(%esp)
639         ret
640
641 /* ssdtosd(*ssdp,*sdp) */
642 ENTRY(ssdtosd)
643         pushl   %ebx
644         movl    8(%esp),%ecx
645         movl    8(%ecx),%ebx
646         shll    $16,%ebx
647         movl    (%ecx),%edx
648         roll    $16,%edx
649         movb    %dh,%bl
650         movb    %dl,%bh
651         rorl    $8,%ebx
652         movl    4(%ecx),%eax
653         movw    %ax,%dx
654         andl    $0xf0000,%eax
655         orl     %eax,%ebx
656         movl    12(%esp),%ecx
657         movl    %edx,(%ecx)
658         movl    %ebx,4(%ecx)
659         popl    %ebx
660         ret
661
662 /* load_cr0(cr0) */
663 ENTRY(load_cr0)
664         movl    4(%esp),%eax
665         movl    %eax,%cr0
666         ret
667
668 /* rcr0() */
669 ENTRY(rcr0)
670         movl    %cr0,%eax
671         ret
672
673 /* rcr3() */
674 ENTRY(rcr3)
675         movl    %cr3,%eax
676         ret
677
678 /* void load_cr3(caddr_t cr3) */
679 ENTRY(load_cr3)
680 #if defined(SWTCH_OPTIM_STATS)
681         incl    _tlb_flush_count
682 #endif
683         movl    4(%esp),%eax
684         movl    %eax,%cr3
685         ret
686
687 /* rcr4() */
688 ENTRY(rcr4)
689         movl    %cr4,%eax
690         ret
691
692 /* void load_cr4(caddr_t cr4) */
693 ENTRY(load_cr4)
694         movl    4(%esp),%eax
695         movl    %eax,%cr4
696         ret
697
698 /* void reset_dbregs() */
699 ENTRY(reset_dbregs)
700         movl    $0,%eax
701         movl    %eax,%dr7     /* disable all breapoints first */
702         movl    %eax,%dr0
703         movl    %eax,%dr1
704         movl    %eax,%dr2
705         movl    %eax,%dr3
706         movl    %eax,%dr6
707         ret
708
709 /*****************************************************************************/
710 /* setjump, longjump                                                         */
711 /*****************************************************************************/
712
713 ENTRY(setjmp)
714         movl    4(%esp),%eax
715         movl    %ebx,(%eax)                     /* save ebx */
716         movl    %esp,4(%eax)                    /* save esp */
717         movl    %ebp,8(%eax)                    /* save ebp */
718         movl    %esi,12(%eax)                   /* save esi */
719         movl    %edi,16(%eax)                   /* save edi */
720         movl    (%esp),%edx                     /* get rta */
721         movl    %edx,20(%eax)                   /* save eip */
722         xorl    %eax,%eax                       /* return(0); */
723         ret
724
725 ENTRY(longjmp)
726         movl    4(%esp),%eax
727         movl    (%eax),%ebx                     /* restore ebx */
728         movl    4(%eax),%esp                    /* restore esp */
729         movl    8(%eax),%ebp                    /* restore ebp */
730         movl    12(%eax),%esi                   /* restore esi */
731         movl    16(%eax),%edi                   /* restore edi */
732         movl    20(%eax),%edx                   /* get rta */
733         movl    %edx,(%esp)                     /* put in return frame */
734         xorl    %eax,%eax                       /* return(1); */
735         incl    %eax
736         ret
737
738 /*
739  * Support for BB-profiling (gcc -a).  The kernbb program will extract
740  * the data from the kernel.
741  */
742
743         .data
744         ALIGN_DATA
745         .globl bbhead
746 bbhead:
747         .long 0
748
749         .text
750 NON_GPROF_ENTRY(__bb_init_func)
751         movl    4(%esp),%eax
752         movl    $1,(%eax)
753         movl    bbhead,%edx
754         movl    %edx,16(%eax)
755         movl    %eax,bbhead
756         .byte   0xc3                            /* avoid macro for `ret' */