在循环x86-64程序集之前和内部使用printf [英] using printf before and inside a loop x86-64 assembly

查看:106
本文介绍了在循环x86-64程序集之前和内部使用printf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在弄清楚如何在此功能中正确使用printf时遇到了麻烦.因此,该函数称为multInts,应该将第一个数组的第一个元素与第二个数组的第一个元素相乘,然后继续遍历整个数组.但是,实验说明指定我不能在main函数中调用printf.因此,我需要打印出"Products:\ n"一词,然后在每一行中打印出产品.但是,我不知道如何在循环中使用printf.讲师说我们应该在计算乘积后在循环中调用printf",还应该在调用printf之前保存并恢复调用者保存的寄存器",但是我不确定这意味着什么. 到目前为止,这是我的代码:

I'm having trouble figuring out how to use printf correctly in this function. So the function is called multInts and is supposed to multiply the first element of the first array with the first element of the second array and continue through the whole array. However, the lab instructions specify that I can't call printf in the main function. So, I need to print out the word "Products:\n" and then in each new line after that, print out the product. I don't know how to use printf within the loop, however. The instructor said that we should "call printf in the loop after calculating product" and also to "save and restore caller-save registers before calling printf," but I'm not sure what that means. Here's what my code looks like so far:

.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?

What I've tried to do is just move the printf instruction to before the loop, but it gives me a segmentation fault when trying to run the loop because %rdi and %rsi contain the addresses of the arrays that need to be used in the loop. How do I get around that and which registers should I use? Also, how do I call printf within the loop?

输出应如下所示:

Products:
200
-925
1386
-2928
-520

推荐答案

保护寄存器免受子例程访问的最简单方法是对其进行push.根据 ABI V调用约定 printf可以更改除RBX之外的任何寄存器. ,RBPR12–R15.您需要保留的寄存器是RAXRDXRSIRDIR8R11(不再需要RCX),因此在调用push >并随后pop它们:

The easiest way to protect a register from being accessed by a subroutine is to push it. According to the ABI V calling convention printf may change any register except RBX, RBP, R12–R15. The registers you need to preserve are RAX, RDX, RSI, RDI, R8 and R11 (RCX is no longer needed), so push before the call to printf and pop them afterwards:

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,您都必须考虑需要保护的内容:

Now, you can copy the block into the loop. For each printf, you have to think about what needs to be secured:

...
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仅处理RDI的低32位.请使用.string %lli \n.

BTW: .string "%i \n" will force printf only to process the lower 32-bit of RDI. Use .string %lli \n instead.

这篇关于在循环x86-64程序集之前和内部使用printf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆