В этом коде:
lea ax,[array]
push ax
fld dword ptr[bp-8]
fstp sum
Вы загружаете адрес array
в AX, а не значение. Затем вы помещаете адрес array
в AX в стек. Затем ваша инструкция FLD
пытается считать данные с фиксированного смещения относительно BP. Как указывает @Jester, вы не должны полагаться на то, что данные в стеке представляют собой конкретное смещение от BP, поскольку это зависит от генератора кода Turbo-C и от того, где элементы размещены в стеке.
Если вы хотите прочитать третий элемент массива, вы можете загрузить адрес массива, а затем получить доступ к адресам отдельных элементов. Загрузите адрес array
в регистры BX, SI или DI, поскольку их можно использовать в качестве базы в 16-битный режим адресации (AX не может).
Ваш код мог бы выглядеть так:
#include<stdio.h>
void main()
{
float array[] = { 1.13,1.98,1.67,1.19 }, sum;
asm{
lea bx,[array] /* Load address of array into BX */
fld dword ptr[bx+8] /* Load the value at 3rd element. Each float is 4 bytes
in 16-bit Turbo-C thus [bx+8] is the third element */
fstp [sum] /* Store top of stack ST(0) to SUM and pop top of stack */
}
printf("%f", sum);
}
Код, который будет суммировать массив с плавающей запятой от самого высокого до самого низкого элемента массива, может выглядеть так:
#include<stdio.h>
void main()
{
float array[] = { 1.13,1.98,1.67,1.19 }, sum;
const int array_size_b = sizeof (array);
/* Size of array in bytes */
asm {
lea bx,[array] /* Load address of array into BX */
mov si, [array_size_b]
/* SI = byte offset to element just past end of array */
fldz /* Push an initial SUM value (0.0) on the FPU stack */
}
sumloop:
asm {
fadd dword ptr[bx+si-4]
/* Add current float to SUM on top of FPU stack */
sub si, 4 /* Set index to previous float in array */
jnz sumloop /* If not start of array go back and process next element */
fstp [sum] /* Retrieve SUM from top of FPU stack&store in variable sum */
}
printf("%f", sum);
}
Обработка элементов в обратном порядке упрощает логику проверки того, обработали ли мы весь массив. Это можно было бы сделать от первого элемента до последнего:
#include<stdio.h>
void main()
{
float array[] = { 1.13,1.98,1.67,1.19 }, sum;
const int array_size_b = sizeof (array);
asm {
lea bx,[array] /* Load address of array into BX */
xor si, si /* SI = index into array = 0 = first element */
mov cx, [array_size_b]
/* CX = byte offset of element just past end of array */
fldz /* Push an initial SUM value (0.0) on the FPU stack */
}
sumloop:
asm {
fadd dword ptr[bx+si]/* Add the current float to SUM on top of FPU stack */
add si, 4 /* Advance index to next float in array */
cmp si, cx /* Has the index reached the end of array? */
jl sumloop /* If not end of array go back and process next element */
fstp [sum] /* Retrieve SUM from top of FPU stack&store in variable sum */
}
printf("%f", sum);
}
Наблюдения
Фактически существует два типа стеков на процессорах с x87 FPU (блок с плавающей запятой). Стек вызовов, на который указывает SS:SP, и стек регистров x87 FPU. Если вы помещаете что-то в стек вызовов, инструкции стека FPU, которые извлекают верхний элемент, извлекаются только из стека регистров FPU. Если вы помещаете что-то в стек вызовов с помощью push ax
, вы нарушаете балансировку стека вызовов, и вам следует подумать о его повторной балансировке, когда ваша встроенная сборка будет завершена. Вы можете использовать pop ax
для этого или add sp, 2
.
person
Michael Petch
schedule
05.08.2019
push ax
того, что вы никогда неpop
, кажется верным путем к неприятностям. - person Nate Eldredge   schedule 05.08.2019bp-8
. - person Jester   schedule 05.08.2019