汇编:如何return一个指针?
Assembly: How to return a pointer?
函数 inventory 获取设备指针数组并调用 evaluate 以找出变化是什么。然后库存函数 returns 一个具有最高变化的指针。
unsigned short evaluate(Struct Device *thing);
struct Device *inventory(struct Device *things[], int count);
device.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: # 计算平均值和returns变异性
movq %r11, %rax
sarq , %rax
movl %eax, 36(%rdi)
subq %rcx, %rdx
movq %rdx, %rax
evaluate.s: # 调用校准和 returns 可变性
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 [=16=], %r12
jge loop
movq %r13, %rsi
movq $.LC0, %rdi
movq [=16=], %rax
call printf
movq %r15, %rdx
movq %r14, %rsi
movq $.LC1, %rdi
movq [=16=], %rax
call printf
movq %r15, %rax
I 运行 程序,结果是:r14 正确获得最高变化,但 LC0 打印正确的最高变化 (r14) 但空名称 (r15),以及试图打印的 C 程序rax中存储的名字也是空的,print语句打印:
与
的最大差异为 65534
相反,它应该打印:
Fell down stairs 的最大变化是 65534
正如您从上面看到的那样,名称没有被打印出来。
经过进一步排查,我发现r15的指针是正确的,它的adjustment和avg值也是正确的,只是name是空字符串,知道为什么吗?也许是因为名称是一个字符数组,并且没有被正确复制?
谢谢!
错误
错误是 movl %eax, 36(%rdi)
在 calibrate.s
的第 38 行。这显然应该写入相关 Device
的 avg
成员,但它是一个 32 位存储,而 Device::avg
是一个 16 位 short
。所以应该是movw %ax, 36(%rdi)
.
我是如何用 gdb 找到它的
希望这会提供一些关于 gdb 可以做什么以及如何有效使用它的信息。
我在inventory
中的第二个printf
设置了一个断点,此时我x/s $rdx
查看字符串%rdx
指向什么:
(gdb) x/s $rdx
0x4040ac <things+76>: ""
好的,所以它是一个空字符串,但它在 things
内的偏移量 76
处,您可以检查它是 things[2].name
的地址。这不应该是一个空字符串,所以让我们看看 things
.
发生了什么
(gdb) p things
= {{name = "Museum Quality[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {0, 1, 0, -1, 0, -1, 0, 1},
avg = 0}, {name = "[=11=]0[=11=]0ll off truck[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767}, avg = 32767}, {name = "[=11=]0[=11=]0ll down stairs[=11=]0[=11=]0[=11=]0",
adjustments = {32752, -32753, 32766, -32767, 32765, -32766, 32767, 32512}, avg = 8159}, {
name = "[=11=]0[=11=]0 left side[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {10, 11, 10, 12, 10, 13,
10, 14}, avg = 11}, {name = "[=11=]0[=11=]0 right side[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {-300,
-321, -320, -332, -320, -313, -310, -314}, avg = -317}}
嗯,things[2].name
的前两个字节现在为空,其他几个字节也为空。这不是它们的初始化方式,根本不应该修改名称,那是怎么发生的呢?一个观察点会告诉我们哪个指令是错误的。
(gdb) watch things[1].name[0]
Hardware watchpoint 3: things[1].name[0]
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
...
Hardware watchpoint 3: things[1].name[0]
Old value = 70 'F'
New value = 0 '[=12=]0'
calibrate () at calibrate.s:39
39 subq %rcx, %rdx
请注意,这是 在 触发观察点的指令之后的指令。所以我们回到第 38 行,想一想,我们到了。
函数 inventory 获取设备指针数组并调用 evaluate 以找出变化是什么。然后库存函数 returns 一个具有最高变化的指针。
unsigned short evaluate(Struct Device *thing);
struct Device *inventory(struct Device *things[], int count);
device.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: # 计算平均值和returns变异性
movq %r11, %rax
sarq , %rax
movl %eax, 36(%rdi)
subq %rcx, %rdx
movq %rdx, %rax
evaluate.s: # 调用校准和 returns 可变性
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 [=16=], %r12
jge loop
movq %r13, %rsi
movq $.LC0, %rdi
movq [=16=], %rax
call printf
movq %r15, %rdx
movq %r14, %rsi
movq $.LC1, %rdi
movq [=16=], %rax
call printf
movq %r15, %rax
I 运行 程序,结果是:r14 正确获得最高变化,但 LC0 打印正确的最高变化 (r14) 但空名称 (r15),以及试图打印的 C 程序rax中存储的名字也是空的,print语句打印:
与
的最大差异为 65534相反,它应该打印:
Fell down stairs 的最大变化是 65534
正如您从上面看到的那样,名称没有被打印出来。
经过进一步排查,我发现r15的指针是正确的,它的adjustment和avg值也是正确的,只是name是空字符串,知道为什么吗?也许是因为名称是一个字符数组,并且没有被正确复制?
谢谢!
错误
错误是 movl %eax, 36(%rdi)
在 calibrate.s
的第 38 行。这显然应该写入相关 Device
的 avg
成员,但它是一个 32 位存储,而 Device::avg
是一个 16 位 short
。所以应该是movw %ax, 36(%rdi)
.
我是如何用 gdb 找到它的
希望这会提供一些关于 gdb 可以做什么以及如何有效使用它的信息。
我在inventory
中的第二个printf
设置了一个断点,此时我x/s $rdx
查看字符串%rdx
指向什么:
(gdb) x/s $rdx
0x4040ac <things+76>: ""
好的,所以它是一个空字符串,但它在 things
内的偏移量 76
处,您可以检查它是 things[2].name
的地址。这不应该是一个空字符串,所以让我们看看 things
.
(gdb) p things
= {{name = "Museum Quality[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {0, 1, 0, -1, 0, -1, 0, 1},
avg = 0}, {name = "[=11=]0[=11=]0ll off truck[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767}, avg = 32767}, {name = "[=11=]0[=11=]0ll down stairs[=11=]0[=11=]0[=11=]0",
adjustments = {32752, -32753, 32766, -32767, 32765, -32766, 32767, 32512}, avg = 8159}, {
name = "[=11=]0[=11=]0 left side[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {10, 11, 10, 12, 10, 13,
10, 14}, avg = 11}, {name = "[=11=]0[=11=]0 right side[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0[=11=]0", adjustments = {-300,
-321, -320, -332, -320, -313, -310, -314}, avg = -317}}
嗯,things[2].name
的前两个字节现在为空,其他几个字节也为空。这不是它们的初始化方式,根本不应该修改名称,那是怎么发生的呢?一个观察点会告诉我们哪个指令是错误的。
(gdb) watch things[1].name[0]
Hardware watchpoint 3: things[1].name[0]
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
...
Hardware watchpoint 3: things[1].name[0]
Old value = 70 'F'
New value = 0 '[=12=]0'
calibrate () at calibrate.s:39
39 subq %rcx, %rdx
请注意,这是 在 触发观察点的指令之后的指令。所以我们回到第 38 行,想一想,我们到了。