.macro save reg pushl %ecx pushl %edx pushl %ebx pushl %esi pushl %edi pushl %ebp .endm .macro restore reg popl %ebp popl %edi popl %esi popl %ebx popl %edx popl %ecx .endm .macro savereg reg pushl \reg .endm .macro restorereg reg popl \reg .endm .macro dumpreg reg pusha pushl \reg pushl $fmt_reg call printf addl $8,%esp popa .endm .global main .data .align 4 bitmap: .long 0 .text fmt_reg: .string "reg 0x%x\n" .align 4 mark_used_table: .long 0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f /* * This assumes that num bits is > 0. */ .align 4 mark_used: savereg %edx #movl 8(%esp),%eax #bitmap #movl 12(%esp),%ecx #num bits #movl 16(%esp),%edx #first bit/bit movl 12(%esp),%eax #num bits movl $8,%ecx #8 bits per loop cycle div %ecx /* * At this point %eax is the quotient and edx is the remainder. */ dumpreg %edx movl mark_used_table(,%edx,4),%eax dumpreg %eax movl $5f,%eax dumpreg %eax call abort 0: bts %edx,(%eax) addl $1,%edx 7: bts %edx,(%eax) addl $1,%edx 6: bts %edx,(%eax) addl $1,%edx 5: bts %edx,(%eax) addl $1,%edx 4: bts %edx,(%eax) addl $1,%edx 3: bts %edx,(%eax) addl $1,%edx 2: bts %edx,(%eax) addl $1,%edx 1: bts %edx,(%eax) addl $1,%edx restorereg %edx ret 1: /* * Ideally we should unroll this loop, and set more bits at once. */ bts %edx,(%eax) jc 3f restorereg %edx ret .align 4 mark_used_old: savereg %edx movl 8(%esp),%eax #bitmap movl 12(%esp),%ecx #num bits movl 16(%esp),%edx #first bit/bit 1: /* * Ideally we should unroll this loop, and set more bits at once. */ bts %edx,(%eax) jc 3f subl $1,%ecx #1 fewer bit to set addl $1,%edx #next bit cmpl $8,%edx jl 2f addl $1,%eax #advance to the next byte. movl $0,%edx 2: cmpl $0,%ecx jg 1b restorereg %edx ret 3: pushl $(5f - 4f) pushl $4f pushl $2 #stderr call write call abort 4: .string "ERROR: bit already set\n" 5: .align 4 find: xor %ecx,%ecx #bits found #xor %edx,%edx #bits requested movl $5,%edx movl bitmap,%eax xor %edi,%edi #bit xor %esi,%esi #initial free bit /* * Unroll the bit tests 8 times for performance. */ movl $0,%esi #initial free bit /* * We are targeting <= i686, so we can't use cmovnc :( * TODO test with the AMD box... */ bt $0,%eax jnc 1f #set movl $1,%esi 1: bt $1,%eax jnc 2f movl $2,%esi 2: bt $2,%eax jnc 3f movl $3,%esi 3: bt $3,%eax jnc 4f movl $4,%esi 4: bt $4,%eax jnc 5f movl $5,%esi 5: bt $5,%eax jnc 6f movl $6,%esi 6: bt $6,%eax jnc 7f movl $7,%esi 7: bt $7,%eax jnc 8f movl $-1,%esi 8: pushl %esi pushl $fmt_first call printf addl $8,%esp ret 1: pushl %edi pushl $fmt_set call printf addl $8,%esp ret ret fmt_first: .string "the first free bit was %d\n" fmt_set: .string "(starting at 0) bit: %d already set\n" fmt_all_8_free: .string "all 8 are free\n" fmt: .string "got jc\n" .align 4 main: movl $2,%eax save call find restore pushl $2000 call malloc cmpl $0,%eax jne 1f call abort 1: addl $4,%esp movl %eax,bitmap pushl $2000 pushl $0 pushl %eax call memset addl $12,%esp pushl $3 #bit offset pushl $181 #number of bits to set movl bitmap,%eax pushl %eax call mark_used addl $12,%esp mov bitmap,%eax mov (%eax),%ecx dumpreg %ecx jmp (1f + (2f - 1f)) 1: ret call abort 2: ret 1: pushl $fmt call printf addl $4,%esp ret