【发布时间】:2020-10-17 09:15:47
【问题描述】:
我正在尝试将68000处理器的可执行文件反编译成C代码,将原来的子程序一一替换为C函数。
我面临的问题是我不知道如何让 gcc 使用与原始程序中使用的调用约定相匹配的调用约定。我需要将堆栈上的参数打包,而不是对齐。
假设我们有以下函数
int fun(char arg1, short arg2, int arg3) {
return arg1 + arg2 + arg3;
}
如果我们编译它
gcc -m68000 -Os -fomit-frame-pointer -S source.c
我们得到以下输出
fun:
move.b 7(%sp),%d0
ext.w %d0
move.w 10(%sp),%a0
lea (%a0,%d0.w),%a0
move.l %a0,%d0
add.l 12(%sp),%d0
rts
如我们所见,编译器假定参数的地址为7(%sp)、10(%sp) 和12(%sp):
但要使用原始程序,他们需要有地址 4(%sp)、5(%sp) 和 7(%sp):
一种可能的解决方案是按以下方式编写函数(处理器为大端):
int fun(int bytes4to7, int bytes8to11) {
char arg1 = bytes4to7>>24;
short arg2 = (bytes4to7>>8)&0xffff;
int arg3 = ((bytes4to7&0xff)<<24) | (bytes8to11>>8);
return arg1 + arg2 + arg3;
}
但是,代码看起来很乱,我想知道:有没有办法既保持代码干净又达到预期的结果?
UPD:我搞错了。我正在寻找的偏移量实际上是5(%sp)、6(%sp) 和8(%sp)(char-s 应该与 short-s 对齐,但 short-s 和 int-s 仍然打包):
希望这不会改变问题的本质。
UPD 2:事实证明,Sierra Systems 的 68000 C 编译器给出了所描述的偏移量(如 UPD 中,2 字节对齐)。
但是,问题在于调整 gcc(或者可能是另一个现代编译器)中的调用约定。
【问题讨论】:
-
According to this 68000 和 68010 不支持非对齐访问,但 68020 支持。所以我会尝试
-m68020。另一种可能性是fun(int base)和struct packedArgs *args = &base;,其中struct packedArgs是包含三个参数的压缩结构。 -
反转参数的顺序
-
@user3386109:
-m68020不会改变 ABI / 调用约定;这可能是必要的(这点很好)但还不够。 -
随着更新,您的问题更有意义。在 68000/68010 上通过
4(%sp)、5(%sp)和7(%sp)传递参数会非常昂贵。 -
您的更新实际上是一个巨大的变化。第一个版本非常奇怪,有一个未对齐的
short和未对齐的long,这是一个理智的编译器永远不会使用的调用约定,并且实际上不能在 68000 上使用,除非被调用者使用多个指令分别加载字节并移动它们一起。 (如果 cmets 是正确的,那么 68000 根本不会进行未对齐的加载;我忘记了)。如果 m68k 支持 2 字节对齐的 4 字节加载,那么带有 2 字节堆栈槽的调用约定是完全合理的alignof(int32_t) = 2。
标签: c assembly gcc calling-convention 68000