использование printf до и внутри сборки x86-64 цикла - PullRequest
0 голосов
/ 26 ноября 2018

Мне сложно понять, как правильно использовать printf в этой функции.Таким образом, функция называется multInts и должна умножить первый элемент первого массива на первый элемент второго массива и продолжить весь массив.Однако в лабораторных инструкциях указано, что я не могу вызвать printf в основной функции.Итак, мне нужно распечатать слово «Продукты: \ n», а затем в каждой новой строке распечатать продукт.Однако я не знаю, как использовать printf в цикле.Инструктор сказал, что мы должны «вызвать printf в цикле после вычисления продукта», а также «сохранить и восстановить регистры сохранения вызовов перед вызовом printf», но я не уверен, что это значит.Вот как выглядит мой код:

.file   "lab4.s"
.section .rodata

.LC0:
    .string "Products: \n"
.LC1: 
    .string "%i \n"
.data
sizeIntArrays:
    .long 5
sizeShortArrays:
    .word 4
intArray1:
    .long 10
    .long 25
    .long 33
    .long 48
    .long 52
intArray2:
    .long 20
    .long -37
    .long 42
    .long -61
    .long -10

##### MAIN FUNCTION
.text
.globl main
.type main,@function

main:
pushq %rbp
movq %rsp, %rbp

#pass parameters and call other functions
movl sizeIntArrays, %edi    #move size to registers for 1st parameter
leaq intArray1, %rsi        #load effective address of intArray1 to register rsi
leaq intArray2, %rdx        #load effective address of intArray2 to register rdx
call multInts           #call multInts function

movq $0, %rax           #return 0 to caller

movq %rbp, %rsp
popq %rbp
ret
.size main,.-main


##### MULTINTS
.globl multInts
.type multInts,@function

multInts:
pushq %rbp
movq %rsp, %rbp

#add code here for what the functions should do
movq $0, %r8            #initialize index for array access in caller save reg
movq $0, %rcx           #initialize 8 byte caller save result reg

loop0:
cmpl %r8d, %edi         #compare index to size
je exit0            #exit if equal
movslq (%rsi,%r8,4),%rax    # Load a long into RAX
movslq (%rdx,%r8,4),%r11    # Load a long into R11
imulq %r11, %rax            # RAX *= R11
addq %rax, %rcx             # RCX += RAX
incq %r8            #increment index
jmp loop0

exit0:
movq $.LC0, %rdi
movq %rcx, %rsi
movq $0, %rax

call printf

movq %rbp, %rsp
popq %rbp
ret
.size multInts,.-multInts

То, что я пытался сделать, это просто переместить инструкцию printf до цикла, но при попытке запустить цикл возникает ошибка сегментации, потому что% rdi и% rsi содержат адреса массивов, которые необходимо использовать в цикле.Как мне обойти это и какие регистры мне использовать?Кроме того, как я могу вызвать printf в цикле?

Вывод должен выглядеть примерно так:

Products:
200
-925
1386
-2928
-520

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Самый простой способ защитить регистр от доступа к подпрограмме - это push it.В соответствии с соглашением о вызовах ABI V printf может изменять любой регистр, кроме RBX, RBP, R12–R15.Регистры, которые нужно сохранить: RAX, RDX, RSI, RDI, R8 и R11 (RCX больше не требуется), поэтому push перед вызовом printf и pop их потом:

pushq %rax
pushq %rdx
pushq %rsi
pushq %rdi
pushq %r8
pushq %r11
movq $.LC1, %rdi
movq %rax, %rsi
movq $0, %rax
call printf
popq %r11
popq %r8
popq %rdi
popq %rsi
popq %rdx
popq %rax

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

...
multInts:
pushq %rbp
movq %rsp, %rbp

#add code here for what the functions should do

pushq %rdx                  # Preserve registers
pushq %rdi
pushq %rsi
movq $.LC0, %rdi            # Format string (no further values)
movq $0, %rax               # No vector registers used
call printf                 # Call C function
popq %rsi                   # Restore registers
popq %rdi
popq %rdx

movq $0, %r8                #initialize index for array access in caller save reg

loop0:
cmpl %r8d, %edi             #compare index to size
je exit0                    #exit if equal

movslq (%rsi,%r8,4),%rax    # Load a long into RAX
movslq (%rdx,%r8,4),%r11    # Load a long into R11
imulq %r11, %rax            # RAX *= R11

pushq %rax                  # Preserve registers
pushq %rdx
pushq %rsi
pushq %rdi
pushq %r8
pushq %r11
movq $.LC1, %rdi            # Format string
movq %rax, %rsi             # Value
movq $0, %rax               # No vector registers used
call printf                 # Call C function
popq %r11                   # Restore registers
popq %r8
popq %rdi
popq %rsi
popq %rdx
popq %rax

incq %r8                    #increment index
jmp loop0

exit0:

movq %rbp, %rsp
popq %rbp
ret
...

BTW: .string "%i \n" заставит printf обрабатывать только младший 32-битный RDI.Вместо этого используйте .string %lli \n.

0 голосов
/ 26 ноября 2018

Предположим, что printf перекрывает все регистры, перекрывающие вызов ( Какие регистры сохраняются посредством вызова функции linux x86-64 ), и использует разные для всего, что необходимо для выживания после одной итерациицикл к следующему.

Посмотрите на вывод компилятора для примера: напишите версию вашего цикла в C и скомпилируйте ее с помощью -Og.

Очевидно, вам нужно переместить инструкции, которыеустановить аргументы в регистрах (например, строку формата) вместе с call printf.

...