所以我正在尝试学习一点装配,因为我需要它用于计算机体系结构类.我写了一些程序,比如打印Fibonacci序列.
我认识到每当我编写程序时,我都会使用这3行(正如我从比较生成的汇编代码中学gcc到的那样C):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
Run Code Online (Sandbox Code Playgroud)
我有2个问题:
%rbp?使用起来不是很简单%rsp,因为它的内容被移到%rbp了第二行吗?%rsp?我的意思是并非总是16(当我在printf第7行或第8行变量时,我会减去24或减去28我在虚拟机(4 GB RAM),Intel 64位处理器上使用Manjaro 64位
作为编译器项目的一部分,我必须为x86编写GNU汇编代码来比较浮点值.我试图找到有关如何在线进行此操作的资源,据我所知,它的工作原理如下:
假设我要比较的值是浮点堆栈上的唯一值,那么fcomi指令将比较这些值并设置CPU标志,以便je可以使用...指令.
我问,因为这只会有效.例如:
.section .data
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, @function
main:
flds f1
flds f2
fcomi
jg leb
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
Run Code Online (Sandbox Code Playgroud)
即使我认为应该打印"Hallo"也不会打印,如果你切换f1和f2,它仍然不会是一个逻辑上的矛盾.jne并且jl但是似乎做工精细.
我究竟做错了什么?
PS:fcomip只弹出一个值还是同时弹出?
根据Miles Murdoca和Vincent Heuring的"计算机体系结构和组织",
CISC指令不适合流水线架构.为了使流水线有效工作,每条指令都需要与其他指令具有相似性,至少在相对指令复杂性方面如此.
为什么这是真的?指令复杂性是什么意思,并非所有指令都需要一个时钟周期才能开始执行; 如果指令正在读取或写入内存,则需要更长时间,但RISC处理器读取也会写入内存(当然)?
我想知道如何正确地做到这一点,因为我这样做的方式行不通。
当BP用7C00h设置寄存器,然后用 设置SP寄存器BP,然后推送一些ASCII,然后从内存中获取数据以打印它INT 10h,它工作得很好。
mov ax, 7C00h
mov bp, ax
mov sp, bp
push 'A'
mov ah, 0Eh
mov al, [7BFEh]
int 10h
Run Code Online (Sandbox Code Playgroud)
实际输出是
一种
但是当我这样做时:
mov ax, 7C00h
mov ss, ax
mov bp, ax
mov sp, bp
...
Run Code Online (Sandbox Code Playgroud)
它停止工作。中断被调用,光标移动,但没有打印任何内容。设置SS为 0 也不起作用。请伸出援手。
我们的内部程序是用 C 编写的,并广泛使用了snprintf()许多部分,我注意到在使用性能记录/报告进行调试期间,它在以下方面花费了大量时间:
\xe2\x94\x82 _IO_vfprintf_internal(): \xe2\x96\x92\n \xe2\x94\x82 mov -0x510(%rbp),%rdx \xe2\x96\x92\n \xe2\x94\x82 mov %r12,%rsi \xe2\x96\x92\n \xe2\x94\x82 mov %r15,%rdi \xe2\x96\x92\n \xe2\x94\x82 \xe2\x86\x92 callq *0x38(%rax) \xe2\x96\x92\n \xe2\x94\x82 cmp %rax,-0x510(%rbp) \xe2\x96\x92\n \xe2\x94\x82 mov -0x530(%rbp),%r9 \xe2\x96\x92\n \xe2\x94\x82 \xe2\x86\x91 jne 91a \xe2\x96\x92\n \xe2\x94\x82 mov -0x4d0(%rbp),%esi \xe2\x96\x92\n \xe2\x94\x82 mov -0x540(%rbp),%ecx \xe2\x96\x92\n \xe2\x94\x82 mov $0x7fffffff,%eax \xe2\x96\x92\n \xe2\x94\x82 sub %esi,%eax \xe2\x96\x92\n \xe2\x94\x82 add %esi,%ecx \xe2\x96\x92\n \xe2\x94\x82 cltq \xe2\x96\x92\n \xe2\x94\x82 cmp %rax,-0x510(%rbp) \xe2\x96\x92\n \xe2\x94\x82 \xe2\x86\x91 jbe 252b \xe2\x96\x92\n \xe2\x94\x82 \xe2\x86\x91 jmpq 28f0 \xe2\x96\x92\n \xe2\x94\x824a70: xor %eax,%eax \xe2\x96\x92\n …Run Code Online (Sandbox Code Playgroud) 假设我有一个像这样的 nasm 函数:
inc:
mov rax,[rsp + 8]
add [rax],BYTE 1
ret
Run Code Online (Sandbox Code Playgroud)
我这样调用这个函数:
push some_var
call inc
Run Code Online (Sandbox Code Playgroud)
我想通过堆栈将参数传递给函数,因此我压入some_var然后调用我的函数。在函数中,我的项目位于堆栈中的第二个,因此我将其视为:mov rax,[rsp+8]
我的问题是:调用函数后我应该以某种方式从堆栈中弹出我的参数吗?如果是这样,我可以以某种方式从堆栈中删除它,我的意思是弹出它,但不注册?(因为我不再需要这个论点了。)
更新:我发现我可以简单地add rsp,8从堆栈中删除项目。但这是好的做法吗?调用函数后从堆栈中删除参数?
我有一些程序集需要在 OS X (x86-64) 中加载 C 符号。使用 x86,您执行此操作的方式是:
mov rax, some_symbol_name
Run Code Online (Sandbox Code Playgroud)
但是,对于 x86-64,这会导致链接警告:
ld:警告:PIE 已禁用。在代码签名的 PIE 中不允许使用绝对寻址(可能是 -mdynamic-no-pic),但在 Test2.o 的 _main 中使用。
要修复此警告,请不要使用 -mdynamic-no-pic 编译或使用 -Wl,-no_pie 链接
注意:我知道 PIE 是什么,我不想禁用它。以下是我将符号地址加载到寄存器中的一些其他尝试:
movq rax, some_symbol_name ; Link warning
lea rax, [rel some_symbol_name] ; No link warning, but doesn't always get correct address
Run Code Online (Sandbox Code Playgroud)
我真的被这个(看似)简单的问题难住了。我已经查看了 GAS 反汇编,它似乎正在按照上述方式做一些事情lea,但是我无法让 NASM 生成正确的代码。
编辑:作为参考,这是由 GAS 生成的汇编代码:
leaq some_symbol_name(%rip), %rax
Run Code Online (Sandbox Code Playgroud) 我想要做的是使用 Emu8086 启动我的程序来调试我的汇编代码,就好像它是通过带有一些参数的命令行启动的一样。使用 DOSBox,我像这样启动我的程序:program.exe result.txt source.txt(result.txt 和 source.txt 是参数),但它没有按预期方式工作,我需要找出原因。如何“模仿”命令行参数传递到 Emu8086 中?
假设我有一个名为 func 的函数:
PROC func:
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
现在,假设我使用 register ax,bx例如,为了保存它们的初始值,我将它们推送到函数内部的堆栈中。
现在的问题是:在创建堆栈帧之前推送寄存器之间是否有很大的不同:
PROC func:
push bp
push ax
push bx
mov bp, sp
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
还是之后?
PROC func:
push bp
mov bp, sp
push ax
push bx
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
我应该在我的程序中使用什么?一种方法比另一种更好或更“正确”吗?因为我目前使用第一种方法。
在我对问题汇编代码返回数组中最小整数而不是随机返回最后一个或倒数第二个数字的问题中,我提出了使用指令的替代方案cmovcc。我在那里指出:
该
cmov指令似乎所有 AMD64 CPU 都支持。
然而,当时我还没有找到确凿的消息来源来支持这一说法。所以我想发布这个问题来询问这个问题。