Консультация № 187652
30.11.2013, 01:48
124.56 руб.
0 5 0
Здравствуйте! У меня возникли сложности с таким вопросом:
Я походу запутался в адресной арифметике, и не могу нормально обойти массив и загружать данные из ячеек.

NASM 64bit режим. Linux
В принципе не думаю что это эм.. 64битный режим и линукс думаю значения особо не имеют.

Что происходит. Segfault.
Валится с ошибкой потому что я попадаю "не по тому адресу"

Условия задания. откоментированные исходники в приложении.
Да. код кривой и убогий, наверняка можно было бы намного проще сделать работу с вещественными числами ( приходилось лишний раз в память обрашаться).
Заранее спасибо надеюсь на помощь.

Приложение:
;задание 3
;реализовать программу
;рассчитывающую среднее значение целочисленного массива
;результат рассчета должен быть вещественным числом

global main

section .data
array: dq 1,2,3,4,5,6,7,8,9,10 ; констатный массив 8 байтных!!! чисел
two: dw 2
arrLenBytes: equ $-array ; Считаем количество байт в массиве
f_bytesPerElement: dq 4.0 ; q-word ; f - префикс от float
f_zero: dq 0.0

section .bss
i_arrayLenInBytes: resb 8; длина массива в байтах резервируем 8 байт под это
i_element resb 8; временное хранение элемента в памяти
;i_arrayLen: resb 8; длина массива в элементах
f_elementsSum: resq 1;
f_arraylen: resq 1; резервируем qword - 64 бита
f_result: resq 1 ; тут мы будем хранить результат вычислений

section .text
main:
; Рассчитываем длину массива, и записываем ее в памятьcalculateArrayLength
call calculateArrayLength

;сначала обнулить сумму надо.
;чтобы прибавлять не к тому мусору что лежит по данному адрессу
call clearSumCell

;=================== Вот отсюда =======================
mov rcx, [array] ; пытался получить адрес начала массива
mov rdx, [array]
add rdx, i_arrayLenInBytes; ; пытался получить адресс конца массива
;;Зачем? чтобы таким вот образом проитерироваться.
;; в rcx начало массива в rdx конец.
;; постепенно rcx будет инкрементироваться и дипазон сужаться.

cmp rcx, rdx ; как бы сравниваю адреса
jb then ; если адресс попадает в дипазон => т.е. это элемент массива
jae end ; если мы вышли за пределы
then:
mov rax, qword[rcx] ; берем элемент массива и тащим его в rax
mov [i_element], rax ; помещаем в память... для загрузки в сопроцессор

;загружаем в сопросцессор уже из памяти
fild qword [i_element]; загружаем целое слово в плавающий регистр
fld qword[f_elementsSum]; загружаем сумму

fadd st0, st1 ;складываем

;сохраняем сумму
fst qword [f_elementsSum]

add rcx,8 ;8 байт на элемент ... Я думал(ю) что у каждой байтовой ячейки есть свой адрес
; и посколько я хожу по массиву адресса должны быть последовательными.
end:
;============================== там где ниже походу работает


;Загружаем сумму всех чисел.
fld qword[f_elementsSum]
;Делим сумму на количество элементов (f_arraylen)
fdiv qword[f_arraylen]
;Сохраняем результат в память
fst qword[f_result]


call exit
ret

clearSumCell: ;верный способ очистки умножение на ноль.
fld qword[f_elementsSum]
fld qword[f_zero]
fmul st0, st1
fst qword [f_elementsSum]
ret

calculateArrayLength:
; Ищем нормальную длину массива в элементах.
; количествоБайт/4

;игра с перемещениями
mov rax, arrLenBytes
mov [i_arrayLenInBytes], rax
; теперь длина массива в байтах находится в памяти
; место выделено.

fild qword [i_arrayLenInBytes]; загружаем целое слово в плавающий регистр
fdiv qword[f_bytesPerElement]; делим его на два
fst qword[f_arraylen]
; длина массива сохранена в нужном месте
; и представленна в вещественном виде

;mov rax, arrLenBytes
;жdiv dword[two]
;mov [i_arrayLen], rax

ret

exit:
mov rax,60 ; у выхода теперь код 60
mov rdi,0 ; как в C - return 0
syscall ; системный вызов.
ret

Обсуждение

давно
Старший Модератор
31795
6196
30.11.2013, 15:15
общий
64-и битной машины у муня нет, поэтому мои советы имеют только рекомендательный характер.
1)использовать сопроцессор для определения длины массива - плохо, длина массива - целое число, тип- перечисление(0..М или 1..М).
2)размер элемента массива - степень двойки(как правило), т.е. можно использовать команду сдвига.
3)но программировать такие вычисления, мне к примеру лень, по этому пусть считает компилятор:
myData equ DB;DW,DD ... и т.д.
array myData 0;первый или нулевой элемент массива
lenOne equ $- array
myData 1,2,3,4,5,6,7,8,9;остальные элементы
lenArray equ ($-array) div lenOne

приблизительно как-то так.
ps:кодом смогу занятся только в понедельник, если [b]Игорь Витальевич[/b] меня не опередит.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
01.12.2013, 03:22
общий
01.12.2013, 03:28
За советы спасибо.
Задачу решил.

Но комманду сдвига не использовал. Не понял как.. Если я сдвигаю, влево значит возвожу на степень двойки (вроде) и ничего не добиваюсь. Вправо тоже не понятно...
давно
Старший Модератор
31795
6196
01.12.2013, 17:34
общий
сдвиг влево = умножению на 2;
сдвиг вправо = делению на 2.

три сдвига вправо = делению на 8(23)
У Вас зарезервированно 80 байт(0101 0000), после трех сдвигов вправо будет 10(0101 0000).
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
03.12.2013, 22:09
общий
04.12.2013, 11:46
Как-то так
Код:

global main
section .data
array: dq 1
len1: equ $-array;длина одного элемента
dq 2,3,4,5,6,7,8,9,10 ; констатный массив 8 байтных чисел
count: equ ($-array)/ len1;считаем количество элементов массива
dq count;запоминаем в память
section .bss
f_result: resq 1 ; тут мы будем хранить результат вычислений;
section .text
main:
;установка начальных значений
mov rsi,array
mov rcx,count
FLDZ
;цикл суммирования
isLoopI:
FILD qword[rsi]
FADD
add rsi,len1
loop isLoopI
;деление
FDIV qword[rsi]
FST qword[f_result]
;дальше код выхода
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
05.12.2013, 17:37
общий
Адресаты:
Большое спасибо за помощь.
Форма ответа