【问题标题】:8086/386 asm with bcc5: returning long int from asm proc带有 bcc5 的 8086/386 asm:从 asm proc 返回 long int
【发布时间】:2012-12-18 02:53:36
【问题描述】:

尝试通过 eax 从 asm proc 返回一个 long int,然后尝试通过 dx:ax。两者都对我不起作用,因为 C printf 打印的数字与所需的 320L 不同。

x.asm:

.model SMALL
.stack 100h
.code
.386
; extern int get_buffered_long(long int **arr, int num_of_elements, int i);
;                                   [BP+4]      [BP+6]              [BP+8]
PUBLIC _get_bufferred_long 
_get_bufferred_long PROC NEAR
        push BP
        mov BP,SP
        push SI
        push DI
        push BX
        call locate_slot            
        ;mov EAX, DWORD PTR [DI]     ;something here doesn't work. the way i return a long int to borland C, or other issue.
        mov ax,[DI]
        mov dx,[DI+2]
        pop BX
        pop DI
        pop SI
        pop BP
        ret
_get_bufferred_long ENDP
; extern void set_bufferred_long(long int *arr[], int buff_size, int i,long int value);
;                                       [BP+4]      [BP+6]      [BP+8]      [BP+10]
PUBLIC _set_bufferred_long
_set_bufferred_long PROC NEAR
    push BP
    mov BP,SP
    pushad
    call locate_slot
    mov EAX,[BP+10]
    mov DWORD PTR [DI],EAX
    popad
    pop BP
    ret
_set_bufferred_long ENDP
; helper function that makes DI point to the slot wanted.
locate_slot PROC NEAR
    calc_slot:
        mov SI,[BP+4]
        mov AX,[BP+8]
        mov BX,[BP+6]
        xor DX,DX
        div BX
    locate_slot_in_array:
        shl AX,1
        add SI,AX
        mov DI,[SI]
        shl DX,2
        add DI,DX
        ret
locate_slot ENDP
end

y.c:

#include "stdio.h"
#include "stdlib.h"

extern int get_bufferred_long(long int**,int,int);
extern void set_bufferred_long(long int**,int,int,long int);

int main(){
    long int **arr;
    int i,j,n,m;
    n = 5;
    m = 4;
    arr=(long int**)malloc(n*sizeof(long int*));
    for(i=0; i < n; i = i + 2) arr[i] = malloc( m*sizeof(long int));
    for(i=1; i < n; i = i + 2) arr[i] = malloc( m*sizeof(long int));
    for(i=0; i < n; i++)
        for(j=0; j < m; j++) 
            set_bufferred_long(arr, m, i*m+j, i*100+j*10);

    printf("get_bufferred_long(arr, %d, %d) = %ld\n", m, 14, get_bufferred_long(arr,m, 14));
    return 0;
}

set 函数有效(数组看起来与需要的完全一样)。 get 函数也可以,它在 asm 中获取 320L,但是当传递给 C 时,出现了问题。

没有编译错误或警告。 borland c++ 5.02

【问题讨论】:

  • 您是否考虑过将您的工具链升级到比 15 年前发布的新版本? gcc 既不含啤酒又不含语音,而 Visual C++ Express 至少不含啤酒。我希望你有充分的理由使用死技术进行开发。
  • @paxdiablo: uni hw,被压倒了。

标签: c assembly long-integer x86-16 borland-c++


【解决方案1】:

嗯,在 386 bcc 上确实在 16 位模式下使用 AX:DX;不知道32位。

但是看看你的代码!

    ...
    mov dx,[DI+2]
    mov ax,[DI]
    mov dx,[DI+2]
    pop DX
    ...

您正在使用结果加载 DX 寄存器,然后将堆栈弹出到其中,吹走它的值。 DX 不必在简单的过程中通过 push/pop 保存(仅在 DOS ISR 中)。

编辑

好的,我看到您在代码中解决了上述问题。下一个问题很可能是您要声明

/* After execution, return value is assumed to be in AX. */ 
extern int get_bufferred_long(long int**,int,int);

然后期待一个 32 位的返回值。您提到printf 正在推送AX 寄存器。这意味着您正在编译为 16 位代码。如果想要 16 位代码中的 32 位返回值,则必须声明返回值 long 并将其放在 DX:AX 中。

/* After execution, return value is assumed to be in DX:AX reg pair. */
extern long get_bufferred_long(long int**,int,int);

您可以通过使用-S 选项将小程序编译为汇编来验证正确的返回约定。举个例子:

long val(void) { return 0x12345678L; }

查看生成的程序集,看看编译器如何返回这个 long 值。

【讨论】:

  • 关于 pop dx,是的,我在代码中错误地留下了一些东西(在您发表评论之前将其编辑掉)。还是没关系。 printf 打印一个奇怪的数字而不是 320L。 “您可以通过在 printf 使用的模式下编译为程序集并检查来验证这一点。”你能解释一下吗?
  • EAX 自 386 以来一直以 32 位模式存在。
  • @Gene 好。在“call _get..” ax=140h 之后,我在 CPU 窗口的 turbo 调试器中查看了 c 代码(c 代码的汇编形式)。这很棒。之后,编译器执行了“push ax”并将其余变量提供给 printf。
  • 我想我现在看到了。您的 get_bufferred_long 在 C 中声明为返回 int。在 16 位密件抄送中,这将位于 AX 寄存器中。所以推送AX 对编译器来说是完全正确的。如果你想返回一个长的,说extern long get_bufferred_long。然后printf 调用应该根据需要推送DX:AX
猜你喜欢
  • 2015-07-31
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 2015-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多