请原谅我如果这个问题之前已经被提出过。我寻找了类似问题的答案,但是仍然对我的问题感到困惑。所以我还是会提出这个问题。
我正在使用一个名为libexif的C库处理图像数据。我在我的Linux桌面和MIPS板上运行我的应用程序(它使用此库)。
对于特定的图像文件,当我尝试获取创建时间时,我得到了一个错误/无效值。进一步调试后,我发现对于这个特定的图像文件,我没有像预期那样获得标签(EXIF_TAG_DATE_TIME)。
这个库有几个实用函数。大多数函数的结构如下:
当库试图调查原始数据中标签的存在时,它会调用
在错误情况下,
34687超出了最大可表示int16_t值的范围。因此导致溢出。当我对代码进行轻微修改后,一切似乎都正常工作了。
但由于这是一个相当稳定的库,已经使用了相当长的时间,所以我认为可能我在这里漏掉了什么。此外,这也是其他实用函数的代码结构的一般方式。例如:
让我困惑的是,当我在我的Linux桌面上运行这段代码时,对于错误文件,我看不到任何问题,原始库代码可以正常工作。这使我相信,也许UINT16_MAX和INT16_MAX宏在我的桌面和MIPS板上具有不同的值。但不幸的是,情况并非如此。两者在板子和桌面上打印出相同的值。如果这段代码失败,它也应该在我的桌面上失败。
我在这里错过了什么?任何提示都将不胜感激。
编辑: 调用exif_get_short()的代码如下:
正在使用的交叉编译器是mipsisa32r2el-timesys-linux-gnu-gcc。
我在Qt中使用libexif - Qt媒体中心(实际上libexif是随Qt媒体中心一起提供的)。
编辑2:一些额外的观察: 我注意到了一些奇怪的事情。我在exif_get_short()中放置了打印语句。就在返回之前。
我看到以下输出: TAG -30871 4294936425
编辑3:发布在MIPS板上拍摄的exif_get_short()和exif_get_sshort()汇编代码。
这个库有几个实用函数。大多数函数的结构如下:
int16_t
exif_get_sshort (const unsigned char *buf, ExifByteOrder order)
{
if (!buf) return 0;
switch (order) {
case EXIF_BYTE_ORDER_MOTOROLA:
return ((buf[0] << 8) | buf[1]);
case EXIF_BYTE_ORDER_INTEL:
return ((buf[1] << 8) | buf[0]);
}
/* Won't be reached */
return (0);
}
uint16_t
exif_get_short (const unsigned char *buf, ExifByteOrder order)
{
return (exif_get_sshort (buf, order) & 0xffff);
}
当库试图调查原始数据中标签的存在时,它会调用
exif_get_short()
并将返回值分配给一个枚举类型(int)的变量。在错误情况下,
exif_get_short()
应该返回无符号值(34687),但返回了一个负数(-30871),这混乱了从图像数据中提取整个标签。34687超出了最大可表示int16_t值的范围。因此导致溢出。当我对代码进行轻微修改后,一切似乎都正常工作了。
uint16_t
exif_get_short (const unsigned char *buf, ExifByteOrder order)
{
int temp = (exif_get_sshort (buf, order) & 0xffff);
return temp;
}
但由于这是一个相当稳定的库,已经使用了相当长的时间,所以我认为可能我在这里漏掉了什么。此外,这也是其他实用函数的代码结构的一般方式。例如:
exif_get_long()
调用exif_get_slong()
。然后我将不得不更改所有实用程序函数。让我困惑的是,当我在我的Linux桌面上运行这段代码时,对于错误文件,我看不到任何问题,原始库代码可以正常工作。这使我相信,也许UINT16_MAX和INT16_MAX宏在我的桌面和MIPS板上具有不同的值。但不幸的是,情况并非如此。两者在板子和桌面上打印出相同的值。如果这段代码失败,它也应该在我的桌面上失败。
我在这里错过了什么?任何提示都将不胜感激。
编辑: 调用exif_get_short()的代码如下:
ExifTag tag;
...
tag = exif_get_short (d + offset + 12 * i, data->priv->order);
switch (tag) {
...
...
ExifTag的类型如下:
typedef enum {
EXIF_TAG_GPS_VERSION_ID = 0x0000,
EXIF_TAG_INTEROPERABILITY_INDEX = 0x0001,
...
...
}ExifTag ;
正在使用的交叉编译器是mipsisa32r2el-timesys-linux-gnu-gcc。
CFLAGS = -pipe -mips32r2 -mtune=74kc -mdspr2 -Werror -O3 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
我在Qt中使用libexif - Qt媒体中心(实际上libexif是随Qt媒体中心一起提供的)。
编辑2:一些额外的观察: 我注意到了一些奇怪的事情。我在exif_get_short()中放置了打印语句。就在返回之前。
printf("return_value %d\n %u\n",exif_get_sshort (buf, order) & 0xffff, exif_get_sshort (buf, order) & 0xffff);
return (exif_get_sshort (buf, order) & 0xffff);
我看到以下输出:
return_value 34665 34665
然后我还在调用exif_get_short()的代码中插入了打印语句。
....
tag = exif_get_short (d + offset + 12 * i, data->priv->order);
printf("TAG %d %u\n",tag,tag);
我看到以下输出: TAG -30871 4294936425
编辑3:发布在MIPS板上拍摄的exif_get_short()和exif_get_sshort()汇编代码。
.file 1 "exif-utils.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 1
.abicalls
.text
.align 2
.globl exif_get_sshort
.ent exif_get_sshort
.type exif_get_sshort, @function
exif_get_sshort:
.set nomips16
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
.set noreorder
.set nomacro
beq $4,$0,$L2
nop
beq $5,$0,$L3
nop
li $2,1 # 0x1
beq $5,$2,$L8
nop
$L2:
j $31
move $2,$0
$L3:
lbu $2,0($4)
lbu $3,1($4)
sll $2,$2,8
or $2,$2,$3
j $31
seh $2,$2
$L8:
lbu $2,1($4)
lbu $3,0($4)
sll $2,$2,8
or $2,$2,$3
j $31
seh $2,$2
.set macro
.set reorder
.end exif_get_sshort
.align 2
.globl exif_get_short
.ent exif_get_short
.type exif_get_short, @function
exif_get_short:
.set nomips16
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
.set noreorder
.cpload $25
.set nomacro
lw $25,%call16(exif_get_sshort)($28)
jr $25
nop
.set macro
.set reorder
.end exif_get_short
为了完整起见,这是我从我的Linux机器中取出的ASM代码。
.file "exif-utils.c"
.text
.p2align 4,,15
.globl exif_get_sshort
.type exif_get_sshort, @function
exif_get_sshort:
.LFB1:
.cfi_startproc
xorl %eax, %eax
testq %rdi, %rdi
je .L2
testl %esi, %esi
jne .L8
movzbl (%rdi), %edx
movzbl 1(%rdi), %eax
sall $8, %edx
orl %edx, %eax
ret
.p2align 4,,10
.p2align 3
.L8:
cmpl $1, %esi
jne .L2
movzbl 1(%rdi), %edx
movzbl (%rdi), %eax
sall $8, %edx
orl %edx, %eax
.L2:
rep
ret
.cfi_endproc
.LFE1:
.size exif_get_sshort, .-exif_get_sshort
.p2align 4,,15
.globl exif_get_short
.type exif_get_short, @function
exif_get_short:
.LFB2:
.cfi_startproc
jmp exif_get_sshort@PLT
.cfi_endproc
.LFE2:
.size exif_get_short, .-exif_get_short
编辑4:希望这是我的最后更新 :-) 使用编译器选项设置为-O1的ASM代码
exif_get_short:
.set nomips16
.frame $sp,32,$31 # vars= 0, regs= 1/0, args= 16, gp= 8
.mask 0x80000000,-4
.fmask 0x00000000,0
.set noreorder
.cpload $25
.set nomacro
addiu $sp,$sp,-32
sw $31,28($sp)
.cprestore 16
lw $25,%call16(exif_get_sshort)($28)
jalr $25
nop
lw $28,16($sp)
andi $2,$2,0xffff
lw $31,28($sp)
j $31
addiu $sp,$sp,32
.set macro
.set reorder
.end exif_get_short
exif_get_short()
的代码吗? 你所做的修改不应该改变exif_get_short()
的行为,而且exif_get_short()
不可能返回负数,因为它返回的是无符号类型(除非定义uint16_t
混乱了)。但是,调用者对返回值可能会做一些错误的操作。另外,在针对MIPS目标时,你使用的编译器和编译时选项是什么? - Michael Burr