【问题标题】:Average of float[] array (Intel 8086)float[] 数组的平均值(英特尔 8086)
【发布时间】:2016-05-08 16:34:01
【问题描述】:

我正在尝试将我的 ANSI C 代码与 ASM(准确地说是 TASM)模块结合起来。
我决定选择经典任务 - 获取数组中数字的平均值,它几乎可以正常工作,它编译和链接成功,但最后它说平均值等于 -0(当它不等于时)。

我做错了什么?这是我的 .c 代码所需的部分:

#include <stdio.h>
extern float avg(int, float*);

int main()
{
  int n = 2;
  float tab[] = {2.0, 3.0};
  printf("%.3g\n", avg(n, tab));

  return 0;
}

.asm程序:

avg PROC
    finit
    push BP
    mov BP, SP

    push bx
    mov cx, [bp+4]      ; no of elements
    mov bx, [bp+8]      ; address

    fldz ; zero
    jcxz avg_end ; if cx==0, end

    iter:
    fadd DWORD PTR [bx]
    add bx, 4
    loop iter

    fidiv DWORD PTR [bp+4] ; sum/n

    avg_end:
    pop bx
    pop BP
    ret
avg ENDP

我的程序内部还有一个外部函数,它运行良好。
唯一的问题必须在avg PROC 代码中。我会很感激你的想法!

【问题讨论】:

  • bx为什么要加8?您确定您的环境中的float 是8 个字节吗?
  • 你真的在写一个 16 位的 DOS 程序吗?如果有,为什么?
  • 在 16 位环境中的参数之间使用偏移量 4 看起来也很奇怪。你确定它在你的 ABI 上吗?
  • 哦,@MikeCAT。这是第一件事。你是对的。我猜应该是4。改变 - 它仍然没有给出正确的答案。但是,当然,谢谢。
  • (我怀疑问题是您将计算结果放在错误的位置,但不知道您意味着要使用什么 ABI,我可以'不能确定或提供更多帮助。)

标签: c assembly x86-16 tasm


【解决方案1】:

在实地址模式下,指针不仅仅是一个偏移量。所以要获取第二个参数 float* 你需要:

lds bx, [bp+8]      ;full pointer

您可能想push ds/pop ds

第一个参数甚至是双字吗?你可以试试:

fidiv WORD PTR [bp+4] ; sum/n

【讨论】:

    【解决方案2】:

    为什么你从不从 FP 堆栈中弹出任何东西?

    在返回之前,您至少错过了最后的fstp DWORD PTR [bp]。分别在您的 ABI 想要将返回值写入的任何位置。

    目前您正在推送到 FP 堆栈,计算平均值,仅此而已。你泄露了一个寄存器,却从未查看过结果。

    【讨论】:

    • 据我所知,如果我返回浮点值,结果应该放在FPU堆栈的顶部st(0)。不是这样吗?
    • 取决于您的编译器选择的 ABI。 hardfpsoftfp。后一个在常规堆栈/寄存器上传递参数和返回值,第一个在 FP 堆栈上推送并期望所有 FP 参数和返回值。仅在cdecl ABI 中,st(0) 用于返回。
    【解决方案3】:

    我明白了。看来我有两个问题:

    • 首先-寻址。
      bx寄存器应该用[bp+6]而不是[bp+8]填充。
      这很明显,因为我的第一个 arg 是整数,2B 长,不是吗?

    • 除此之外,@Sep Roland 对我的 fidiv 指令是正确的。
      我的价值甚至不是 DWORD,它只是 WORD,它解决了我所有的问题。

    现在可以了,谢谢大家的宝贵时间。
    我无法删除我的问题,所以我发布了我的答案,也许有一天它会有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 2011-05-10
      • 2020-11-20
      • 1970-01-01
      相关资源
      最近更新 更多