【发布时间】:2021-07-04 23:11:51
【问题描述】:
inventory 函数接受一个设备指针数组并调用评估来找出变化是什么。然后inventory函数返回一个变化最大的指针。
unsigned short evaluate(Struct Device *thing);
struct Device *inventory(struct Device *things[], int count);
设备.h:
struct Device{
char name[20];
short adjustments[8];
short avg;
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
/* from device.h, shown here to make it easier to code
struct Device
{
char name[20];
short adjustments[8];
short avg;
};
*/
struct Device things[] =
{
{ "Museum Quality",{ 0, 1, 0, -1, 0, -1, 0, 1}, 1 },
{ "Fell off truck",
{ 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff},
2 },
/* the casts are there since C constants are ints and you can't make
* them shorts and negative numbers look like overflow */
{ "Fell down stairs",
{ 0x7ff0, (unsigned short)0x800f, 0x7ffe, (unsigned short)0x8001,
0x7ffd, (unsigned short)0x8002, 0x7fff, 0x7f00},
3 },
{ "On left side",{ 10, 11, 10, 12, 10, 13, 10, 14}, 4 },
{ "On right side",{ -300, -321, -320, -332, -320, -313, -310, -314}, 5 }
};
/*
struct Device *inventory(struct Device *things[], int count);
*/
int main()
{
struct Device *pointers[1 + sizeof(things) / sizeof(things[0])]
= {NULL};
const int count = sizeof(things) / sizeof(things[0]);
struct Device *worst = NULL;
int i;
for (i=0; i< count; i++)
{
printf("Loading %s into pointers\n", things[i].name);
pointers[i] = &things[i];
}
pointers[i] = NULL;
worst = inventory(pointers, count);
printf("main: The worst is %s\n", worst->name);
return(EXIT_SUCCESS);
}
calibrate.s: # 计算平均值并返回可变性
movq %r11, %rax
sarq $3, %rax
movl %eax, 36(%rdi)
subq %rcx, %rdx
movq %rdx, %rax
evaluate.s: # 调用校准并返回可变性
call calibrate
inventory.s:
rdi 是保存设备指针数组的参数,#rbx 是 rdi 的副本,因此它存储设备指针数组,#r12 存储有效指针的计数,#r14 存储最大变化,#r15 存储变化最大的设备指针。
movq %rdi, %r15 #r15 stores pointer with most variable
loop:
movq (%rbx,%r12,8), %rdi
call evaluate
cmpq %r14, %rax
jle skipmax
movq %rax, %r14
movq (%rbx, %r12,8), %r15
skipmax:
decq %r12
cmpq $0, %r12
jge loop
movq %r13, %rsi
movq $.LC0, %rdi
movq $0, %rax
call printf
movq %r15, %rdx
movq %r14, %rsi
movq $.LC1, %rdi
movq $0, %rax
call printf
movq %r15, %rax
我运行程序,结果是:r14 正确地获得了最高变异性,但 LC0 打印了正确的最高变异性 (r14) 但名称为空 (r15),并且试图打印存储在 rax 中的名称的 C 程序是也是空的,打印语句打印:
最大变化是 65534 距离
相反,它应该打印:
最大变化是从楼梯摔下来的 65534
正如您从上面看到的那样,名称没有被打印出来。
经过进一步的故障排除,我发现r15的指针是正确的,它的调整值和平均值都是正确的,只是name是空字符串,知道为什么吗?也许是因为名称是一个字符数组,并且没有正确复制?
谢谢!
【问题讨论】:
-
你试过单步调试器吗?
-
你确定
evaluate遵守 ABI 并且不会破坏 R15,并且它返回一个 64 位整数正确符号扩展为 RAX,而不是int或short或什么?您确定要设备指针,而不是指向设备指针的指针(即指向数组条目的指针)吗?如果是后者,lea而不是mov。如果您确实想要前者,那么我认为错误不在此代码中。 -
请把它变成一个minimal reproducible example,为这个函数以及
evaluate(至少一个存根)提供完整的可构建代码,以及一个main函数,通过适当的输入调用它们.我同意 Peter 的观点,我在这里没有看到任何错误,因此错误必须在您没有向我们展示的代码中。缺少这样的例子就是为什么这个问题已经有 2 票赞成,还有 1 票会反对。 -
并立即确定了罪魁祸首:
movl %eax, 36(%rdi)incalibrate。它应该写入rdi->avg,但它是 32 位移动,avg是 16 位,因此接下来的 2 个字节会被覆盖。让它movw %ax, 36(%rdi)。所以你猜怎么着:这个 bug 不是你想的那样,盯着你最初发布的代码是徒劳的,在完整的代码上运行调试器是相当有效的。 -
@EmperorHan:呃,StackOverflow 真的希望你不要删除它,因为它会使帖子对其他人无用。理想情况下,您应该将代码缩减为可以安全共享的内容。您至少可以留下足够的空间,以便可以看到错误及其原因吗?
标签: loops pointers assembly x86-64