如何告诉gcc不要在堆栈上对齐函数参数?

Max*_*xim 7 c assembly gcc 68000 calling-convention

我试图将68000处理器的一个可执行文件反编译成C代码,用C函数一一替换原来的子程序。

我面临的问题是我不知道如何让 gcc 使用与原始程序中使用的调用约定匹配的调用约定。我需要将堆栈上的参数打包,而不是对齐。

假设我们有以下功能

int fun(char arg1, short arg2, int arg3) {
    return arg1 + arg2 + arg3;
}
Run Code Online (Sandbox Code Playgroud)

如果我们编译它

gcc -m68000 -Os -fomit-frame-pointer -S source.c
Run Code Online (Sandbox Code Playgroud)

我们得到以下输出

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
Run Code Online (Sandbox Code Playgroud)

正如我们所见,编译器假定参数具有地址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;
}
Run Code Online (Sandbox Code Playgroud)

然而,代码看起来很乱,我想知道:有没有办法既保持代码干净又达到预期的结果?


UPD:我犯了一个错误。我正在寻找的偏移量实际上是5(%sp)6(%sp)并且8(%sp)(char-s 应该与 short-s 对齐,但 short-s 和 int-s 仍然被打包):

更新的所需参数位置的图示

希望这不会改变问题的本质。


UPD 2:事实证明,Sierra Systems 的 68000 C 编译器给出了描述的偏移量(如在 UPD 中,2 字节对齐)。

然而,问题是关于在 gcc(或者可能是另一个现代编译器)中调整调用约定。

cht*_*htz 2

要使用 2 字节对齐而不是 4 字节对齐来获取传递的整数参数,您可以将默认int大小更改为 16 位-mshort。您需要将int代码中的所有内容替换为long(如果您希望它们是 32 位宽)。最简单的方法是将其传递-Dint=long给编译器。显然,您将破坏编译目标文件的 ABI 兼容性-mno-short(这似乎是 gcc 的默认设置)。

  • 你是对的,我从有关 [tigcc fork](http://tigcc.ticalc.org/doc/comopts.html) 的页面中选择了该信息,该信息显然不在主线 gcc 中。 (3认同)
  • 我在 GCC 在线文档的 [Option Summary](https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html) 页面上找不到 `-mlong`,但是 [M680x0 Options](https ://gcc.gnu.org/onlinedocs/gcc/M680x0-Options.html)页面显示 `-mno-short` 是默认值。 (2认同)