我使用bt测试装配中是否设置或取消设置某些位。我的代码如下所示:
#define bv %eax //just renaming reg to make reading easier
#define bit %edx //rename reg
/*
* bitIsSetBV(unsigned int *bv, unsigned int bit)
* this function returns 0 if bit at location bit is not set
* it returns 1 if it is set
*/
.text
.global bitIsSetBV
bitIsSetBV:
movl 4(%esp), bv //make room on stack for bv
movl 8(%esp), bit //make room on stack for bit
bt bit, (bv) //if bv[bit] is 0, set CF to 0, else, set CF to 1
jc bitSet // if CF is 1, jump to bitSet
jnc bitNotSet // if CF is 0, jump to bitNotSet
bitNotSet:
movl $0, bv //return 0, bit is not set
jmp Done // jump to Done
bitSet:
movl $1, bv // return 1, bit is set
jmp Done // jump to Done
Done:
ret //end of code
测试仪:
assert(bitIsSetBV(bv, 0) == 1); // 0001 assert(bitIsSetBV(bv, 1) == 0); assert(bitIsSetBV(bv, 2) == 0); assert(bitIsSetBV(bv, 3) == 0); assert(bitIsSetBV(bv, 4) == 0); // 1110 assert(bitIsSetBV(bv, 5) == 1); assert(bitIsSetBV(bv, 6) == 1); assert(bitIsSetBV(bv, 7) == 1);
我的代码适用于bit = 0-5,但是在bit = 6时,它不适用。这是为什么?我确定这是我对比特级别操作的误解。
答案 0 :(得分:2)
这是对您的问题的回复,但不一定是解决方案的答案。虽然你的汇编代码效率很低,但是当我第一次看到它时,我没有看到它的任何逻辑缺陷,所以我认为问题不在你的汇编代码中,而是在 C 代码中的某个地方。我昨晚确实要求您提供 C 代码,但没有跟进。
我从下面的汇编代码中取出了多余的跳转和分支,但是原始代码应该有效。我把它放在一个名为isbitset.S
的汇编文件中:
#define bv %eax //just renaming reg to make reading easier
#define bit %edx //rename reg
/*
* bitIsSetBV(unsigned int *bv, unsigned int bit)
* this function returns 0 if bit at location bit is not set
* it returns 1 if it is set
*/
.text
.global bitIsSetBV
bitIsSetBV:
movl 4(%esp), bv //make room on stack for bv
movl 8(%esp), bit //make room on stack for bit
bt bit, (bv) //if bv[bit] is 0, set CF to 0, else, set CF to 1
jc bitSet // if CF is 1, jump to bitSet
bitNotSet:
movl $0, bv //return 0, bit is not set
jmp Done // jump to Done
bitSet:
movl $1, bv // return 1, bit is set
Done:
ret //end of code
我建议Peter Cordes在评论中提出建议,使代码更有效率。由于我认为关注的是测试程序,我更关心它是如何被调用的。我在名为bittest.c
的 C 中创建了这个简单的测试程序:
#include <assert.h>
extern int bitIsSetBV(unsigned int *bv, unsigned int bit);
int main()
{
unsigned int a = 0xe1; /* which is binary 11100001 */
unsigned int *bv = &a;
assert(bitIsSetBV(bv, 0) == 1); /* 0001 */
assert(bitIsSetBV(bv, 1) == 0);
assert(bitIsSetBV(bv, 2) == 0);
assert(bitIsSetBV(bv, 3) == 0);
assert(bitIsSetBV(bv, 4) == 0); /* 1110 */
assert(bitIsSetBV(bv, 5) == 1);
assert(bitIsSetBV(bv, 6) == 1);
assert(bitIsSetBV(bv, 7) == 1);
return 0;
}
我使用以下命令汇编,编译并将代码链接到名为bittest
的程序:
gcc -m32 -c isbitset.S -o isbitset.o
gcc -m32 bittest.c isbitset.o -o bittest
或者你也可以这样做:
gcc -m32 bittest.c isbitset.S -o bittest
我这样运行:
./bittest
-m32
确保您生成32位可执行文件。如果您在64位系统上进行编译,这可能会产生很大的不同,该系统默认为Linux使用的64-bit System V ABI。您使用32位调用约定编写了汇编代码,因此如果从编译为64位的 C 程序调用它,它将无法工作。
在这种情况下,代码不会生成任何断言,这意味着这些位符合我的预期。
这个答案还提供了Minimal Complete Verifiable Example,并且是您如何创建人们可以测试的问题的示例。