x86-64 Linux NASM. Передача параметра функции массива типа int, объявленного как функция в файле C++

Я пытался использовать этот совет для этой проблемы

Для программирования Linux arr[], n, &a, &b передаются в RDI, RSI, RDX и RCX.

и вывод программы не суммирует целые числа в массиве должным образом. Он выводит большое число, которое явно неверно.

Два файла, найденные ниже, были изменены по сравнению с исходной 32-битной версией, найденной здесь. http://mcs.uwsuper.edu/sb/224/Intro/c_asm.html

Я хочу скомпилировать файл сборки, который вызывает параметр функции в файле C++ с именем array.cpp, а затем связать полученный объектный файл array.o с g++.

Проблема, с которой я столкнулся, связана либо с передачей правильных регистров в стек, либо, возможно, с количеством байтов, которые нужно добавить для каждого смещения в регистре rsi (я использовал 8, поскольку каждый элемент стека имеет 64 бита).

Также может быть, что регистр rbp неправильно загружен с правильными смещениями адреса массива и количества элементов в массиве.

 mov rcx, [rbp+24]   ; array length
 mov rsi, [rbp+16]    ; array address

В любом случае, вот файл array.cpp, а под ним файл nasm, я назвал его nasm_cpp.asm.

Они компилируются, связываются и запускаются с

nasm -f elf64 nasm_cpp.asm -o array.o
g++ -m64 array.cpp array.o
./a.out


#include <iostream>
using namespace std;

extern "C" int array(int a[], int length);   // external ASM procedure

int main()
{
  int a[] = { 10, 10};  // array declaration
  int array_length = 2;                     // length of the array

  int sum = array(a, array_length);          // call of the ASM procedure

  cout << "sum=" << sum << endl;             // displaying the sum
}

Это nasm_cpp.asm ниже

;nasm -f elf64 nasm_cpp.asm -o array.o
;g++ -m64 array.cpp array.o
;./a.out
global array               ; required for linker and NASM
section .text              ; start of the "CODE segment"

array: push rbp           
       mov rbp, rsp        ; set up the rBP
       push rcx            ; save used registers
       push rdi
       push rsi

       mov rcx, [rbp+24]   ; array length
       mov rsi, [rbp+16]    ; array address

       xor rax, rax        ; clear the sum value       
lp:    add rax, [rsi]      ; fetch an array element
       add rsi, 8         ; move to another element
       loop lp             ; loop over all elements

       pop rsi             ; restore used registers
       pop rdi
       pop rcx     
       pop rbp
       ret                 ; return to caller

person pandoragami    schedule 10.08.2017    source источник
comment
Параметры передаются в регистрах на x86-64. Google для SYS V ABI x64   -  person Margaret Bloom    schedule 10.08.2017
comment
Здесь wiki.osdev.org/System_V_ABI написано Parameters to functions are passed in the registers rdi, rsi, rdx, rcx, r8, r9,. Это то, что вы думаете, может решить это? А как насчет rcx рег. Как мне подсчитать, а также сохранить в нем значения перед нажатием стека?   -  person pandoragami    schedule 10.08.2017
comment
Я удалил rcx push и pop, и это все равно не сработало.   -  person pandoragami    schedule 10.08.2017
comment
Вам не нужно нажимать и извлекать rcx, rsi, rdi, потому что они являются энергозависимыми регистрами, которые могут быть изменены функцией и не нуждаются в сохранении. Вы можете увидеть это на Рисунок 3.4: Регистрация использования в 64-битном ABI SysV. Кроме того, самое простое исправление — изменить на mov rcx, rsi ; array length mov rsi, rdi ; array address . Поскольку вы добавляете 32-битные целые числа, вам нужно изменить add rax, [rsi] на add eax, [rsi] и добавить 4 к адресу вместо 8 - изменить add rsi, 8 на add rsi, 4.   -  person Michael Petch    schedule 10.08.2017
comment
Инструкция цикла может быть неэффективной (но она будет работать, хотя и привязывает вас к RCX). Вы можете упростить код, используя RDI для указателя вместо RSI< /i> это устранит дополнительный ход. Вам также не нужен кадр стека, поэтому push rbp mov rbp, rsp в начале и pop rbp также можно удалить.   -  person Michael Petch    schedule 10.08.2017
comment
@Майкл и Маргарет, спасибо! оно работает. Я просто опубликую код ниже, показывающий изменения!   -  person pandoragami    schedule 10.08.2017


Ответы (1)


Я последовал предложениям в комментариях, размещенных под вопросом, и теперь он работает, файл cpp такой же, как указано выше.

;nasm -f elf64 nasm_cpp.asm -o array.o
;g++ -m64 array.cpp array.o
;./a.out
global array               ; required for linker and NASM
section .text              ; start of the "CODE segment"

array:      
       push rbp           
       mov rbp, rsp        ; set up the rBP  

       mov rcx, rsi   ; array length
       mov rsi, rdi    ; array address

       xor rax, rax        ; clear the sum value       
lp:    add eax, [rsi]      ; fetch an array element
       add rsi, 4         ; move to another element
       loop lp             ; loop over all elements    

       pop rbp

       ret                 ; return to caller
person pandoragami    schedule 10.08.2017
comment
Обратите внимание, что ваш код не будет работать, если длина массива равна нулю. Является ли это проблемой, зависит от ваших спецификаций. - person Jester; 10.08.2017
comment
Думаю, я мог бы поставить условное выражение jz outside_loop после cmp rcx,0? - person pandoragami; 10.08.2017
comment
Также есть инструкция jecxz - person Jester; 10.08.2017
comment
Дело принято! @шут - person pandoragami; 11.08.2017