2016-05-08 55 views
1

我在汇编中写入一个无符号长整型函数。 这是一个UTF-8字符。程序集AT&T x86 - 如何比较长特定字节?

我想检查它是否是1个,2个,3个或4个字节的UTF-8字符。到目前为止,我有这样的:(我改变代码不被字节序的影响,我认为...)

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $128,buff  # &-mask 1 MSB (from LSByte) 
cmpl $0,buff   # Compare buff to 0 
je  wu8_1byte  # If 0, 1 byte UTF8 

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $0xE000,buff # &-mask 3 MSB (from byte LSByte 2) 
cmpl $0xC000,buff # Compare the 3 MSB to binary 110 
je  wu8_2byte  # If =, 2 byte UTF8 

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $0xF00000,buff # &-mask 4 MSB (from byte MSByte 3) 
cmpl $0xE00000,buff # Compare the 4 MSB to binary 1110 
je  wu8_3byte  # If =, 3 byte UTF8 

jmp  wu8_4byte  # If no, 4 byte UTF8 

12(%EBP)是长我想工作。 Buff是一个4字节的变量。

它适用于1byte,但不适用于其他。

关于如何弄清楚它是什么类型的UTF-8字符的任何提示?

UTF-8编码:

      0xxxxxxx # 1 byte 
        110xxxxx 10xxxxxx # 2 byte 
     1110xxxx 10xxxxxx 10xxxxxx # 3 byte 
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx # 4 byte 
+0

当你说“这是一个UTF-8字符”时,它是否以大端形式编码?因为这对英特尔来说是不寻常的。 –

+0

我很确定它是什么endianess。我使用gcc -m32编译它,并用C程序测试装配函数。 –

+0

那么事实上,你将13位移动到前端字节的测试部分告诉我,你相信只要UTF-8字节序列以big endian顺序存储就可以了。你的系统的体系结构是小端的。这就是为什么我觉得很奇怪。 –

回答

1

它不应该为任何人工作的原因很简单。

您取一个32位的值并将其右移。然后,你将它与一个常数相比较,忘记了还有比你比较的更多的位。

你必须和值仅获取你想要的位:

movl 12(%ebp),%eax 
movl %eax,buff 
shrb $13,buff #UTF8 2 byte looks like 110xxxxx 10xxxxxx 
andl $7, buff # Take only the three lowest bits 
cmpl $6,buff #Therefore shift 13 spaces right and check 
je wu8_2byte #if buff=6 (110 = 6) 

我还要寄存器内处理它,而不是在一个内存位置,使其更快。你也可以在没有任何班次的情况下做到这一点。

+0

我认为多头从左到右都是0填充。但是,我试过你的解决方案,但它也没有工作。 –

1

根据您想要执行的错误检查的次数,您可以使用test指令简单地测试位。我假设unsigned long已从UTF-8编码字节序列中加载,最低有效字节在前,这应该与在小端机上将char*混淆为unsigned long*的结果相同。

如果这些假设是错误的,那么您可能需要相应地更改代码 - 它可能更复杂,因为您可能不知道哪个字节是前导字节。

E.g.

movl 12(%ebp),%eax 
testl $128,%eax 
jz wu8_1byte 
testl $32,%eax  # We know that the top bit is set, it's not valid for it to be 
        # 10xxxxxx so we test this bit: 11?xxxxx 
jz wu8_2byte 
testl $16,%eax  # 111?xxxx 
jz wu8_3byte 
# Must be 4 byte 
jmp wu8_4byte 

此代码片段与您的原始代码具有相同的假设。

movl 12(%ebp),%eax 

testl $0x80,%eax 
jz wu8_1byte 
        # We can assume that the last byte is of the form 10xxxxxx 
testl $0x7000,%eax # Testing this bit in byte n - 1: 1?xxxxxx 
jnz wu8_2byte 

testl $0x700000,%eax # Testing this bit in byte n - 2: 1?xxxxxx 
jnz wu8_3byte 
# Must be 4 byte 
jmp wu8_4byte 
+1

其他优化可以分散您的答案:'testl $ 128,%eax'可以通过测试'%al'来缩短,甚至可以通过'testl%al,%al' /'jns'分支到最低位的最低位8没有立即的常数。但'test $ imm8,%al'有一个特殊的操作码,所以它仍然是2B指令。此外,'testl $ 0x7000,%eax'可能是'test 0x70,%ah'来保存另外几个字节的机器码。 (读取部分寄存器总是很好,它会写入部分寄存器,可能会导致速度减慢。尽管如此,避免使用'test $ imm16,%ax',但是:使用立即数的16位操作数大小导致LCP失速) –

0

我解决它由UTF-8读取并寻找一个简单的解决方案:

cmpl $0x7F,12(%ebp)  # Compare unsigned long to 1 byte UTF-8 max value 
jbe  wu8_1byte 

cmpl $0x7FF,12(%ebp) # Compare unsigned long to 2 byte UTF-8 max value 
jbe  wu8_2byte 

cmpl $0xFFFF,12(%ebp) # Compare unsigned long to 3 byte UTF-8 max value 
jbe  wu8_3byte 

cmpl $0xFFFFFF,12(%ebp) # Compare unsigned long to 4 byte UTF-8 max value 
jbe  wu8_4byte 

的UTF-8字符的编码的方式,1点字节的字符具有0x7F的的最大值,最大2字节0x7FF,最大3字节0xFFFF,最大4字节0xFFFFFF。所以,通过比较无符号long和这些值,我可以确定解码字符所需的字节数。

+0

尽管我仍然不确定,其中实际数据字节位于,例如:在无符号长整型中:xxxxxxxx(byte0)xxxxxxxx(byte1)xxxxxxxx(byte2)xxxxxxxx(byte3)。其中12(%ebp)是byte0,15(%ebp)是byte3。 UTF-8数据字节在哪里?他们总是从byte0开始?如4字节UTF-8:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx&1字节UTF-8:0xxxxxxx 00000000 00000000 00000000? –