- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想学习汇编编程,以编写快速有效的代码。
我如何偶然遇到无法解决的问题。
我想遍历双字数组并添加其组件,如下所示:
%include "asm_io.inc"
%macro prologue 0
push rbp
mov rbp,rsp
push rbx
push r12
push r13
push r14
push r15
%endmacro
%macro epilogue 0
pop r15
pop r14
pop r13
pop r12
pop rbx
leave
ret
%endmacro
segment .data
string1 db "result: ",0
array dd 1, 2, 3, 4, 5
segment .bss
segment .text
global sum
sum:
prologue
mov rdi, string1
call print_string
mov rbx, array
mov rdx, 0
mov ecx, 5
lp:
mov rax, [rbx]
add rdx, rax
add rbx, 4
loop lp
mov rdi, rdx
call print_int
call print_nl
epilogue
section .rodata
int_format db "%i",0
string_format db "%s",0
section .text
global print_string, print_nl, print_int, read_int
extern printf, scanf, putchar
print_string:
prologue
; string address has to be passed in rdi
mov rsi,rdi
mov rdi,dword string_format
xor rax,rax
call printf
epilogue
print_nl:
prologue
mov rdi,0xA
xor rax,rax
call putchar
epilogue
print_int:
prologue
;integer arg is in rdi
mov rsi, rdi
mov rdi, dword int_format
xor rax,rax
call printf
epilogue
最佳答案
我不确定您的代码为什么打印了错误的数字。您应该通过调试器进行跟踪的某个地方可能是一个一个的地方。具有layout asm
和layout reg
的gdb应该会有所帮助。实际上,我认为您要在数组末尾走一遍。那里可能是-1,然后将其添加到累加器中。
如果您的最终目标是编写快速高效的代码,则应该看看我最近添加到https://stackoverflow.com/tags/x86/info的一些链接。 Esp。 Agner Fog的优化指南非常适合帮助您了解当今机器上有效运行的内容,而哪些行之有效。例如与leave
占用2相比,mov rsp, rbp / pop rbp
较短,但需要3 oups。或者只是省略帧指针。 (这些天,gcc默认将amd64的默认值设置为-fomit-frame-pointer
。)乱七八糟的做法只会浪费指令,而且会浪费您的注册费用,尤其是在注册时。值得在ASM中编写的函数中(即通常所有内容都存放在寄存器中,而您不调用其他函数)。
执行此操作的“常规”方法是在asm中编写函数,从C调用函数以获取结果,然后使用C打印输出。如果希望代码可移植到Windows,则可以使用类似的方法
#define SYSV_ABI __attribute__((sysv_abi))
int SYSV_ABI myfunc(void* dst, const void* src, size_t size, const uint32_t* LH);
这样,即使您为Windows编译,也不必更改ASM在不同的寄存器中查找其args。 (SysV调用约定比Win64更好:寄存器中有更多的args,并且所有 vector 寄存器都可以使用而无需保存它们。)确保您有一个足够新的gcc,它可以修复
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66275。
%define
编码,以便为Windows或SysV ABI汇编相同的源。或者在常规入口之前有一个Windows入口点,该入口点使用一些MOV指令将args放在函数其余部分期望的寄存器中。但这显然效率较低。
print_int
等例程效率极低。 (即使没有使用任何一个,也按/ pop 每个保存有被调用者的寄存器,并且多次调用printf而不是使用以
\n
结尾的单个格式的字符串。)我知道您并不认为此代码是有效的,并且你只是在学习。您可能已经知道这不是很严格的代码。 :P
lp:
mov rax, [rbx]
add rdx, rax
add rbx, 4
loop lp
Never use the loop
instruction。与宏融合的比较和分支的1相比,它解码为7 oups。
loop
的最大吞吐量为每5个周期之一(Intel Sandybridge/Haswell及更高版本)。相比之下,
dec ecx / jnz lp
或
cmp rbx, array_end / jb lp
将使您的循环每个循环运行一次。
add rdx, [rbx]
也比单独的
mov
-load更有效。 (这是使用索引寻址模式
since they can only micro-fuse in the decoders / uop-cache, not in the rest of the pipeline, on Intel SnB-family进行的更复杂的权衡,在这种情况下,
add rdx, [rbx+rsi]
或其他内容将在Haswell和更高版本上保持微融合)。
movs
insn以这种方式隐式使用它们,这就是为什么将它们分别命名为
si
和
di
的原因。但是,切勿仅由于寄存器名称而使用多余的
mov
指令。如果要提高可读性,请将C与良好的编译器一起使用。
;;; This loop probably has lots of off-by-one errors
;;; and doesn't handle array-length being odd
mov rsi, array
lea rdx, [rsi + array_length*4] ; if len is really a compile-time constant, get your assembler to generate it for you.
mov eax, [rsi] ; load first element
mov ebx, [rsi+4] ; load 2nd element
add rsi, 8 ; eliminate this insn by loading array+8 in the first place earlier
; TODO: handle length < 4
ALIGN 16
.loop:
add eax, [ rsi]
add ebx, [4 + rsi]
add rsi, 8
cmp rsi, rdx
jb .loop ; loop while rsi is Below one-past-the-end
; TODO: handle odd-length
add eax, ebx
ret
在调试之前不要使用此代码。 gdb(带有
layout asm
和
layout reg
)还不错,并且在每个Linux发行版中都可用。
segment .rodata ; read-only data
ALIGN 16
array: times 64 dd 1, 2, 3, 4, 5
array_bytes equ $-array
string1 db "result: ",0
segment .text
; TODO: scalar loop until rsi is aligned
; TODO: handle length < 64 bytes
lea rsi, [array + 32]
lea rdx, [rsi - 32 + array_bytes] ; array_length could be a register (or 4*a register, if it's a count).
; lea rdx, [array + array_bytes] ; This way would be lower latency, but more insn bytes, when "array" is a symbol, not a register. We don't need rdx until later.
movdqu xmm0, [rsi - 32] ; load first element
movdqu xmm1, [rsi - 16] ; load 2nd element
; note the more-efficient loop setup that doesn't need an add rsi, 32.
ALIGN 16
.loop:
paddd xmm0, [ rsi] ; add packed dwords
paddd xmm1, [16 + rsi]
add rsi, 32
cmp rsi, rdx
jb .loop ; loop: 4 fused-domain uops
paddd xmm0, xmm1
phaddd xmm0, xmm0 ; horizontal add: SSSE3 phaddd is simple but not optimal. Better to pshufd/paddd
phaddd xmm0, xmm0
movd eax, xmm0
; TODO: scalar cleanup loop
ret
同样,此代码可能存在错误,无法处理对齐和长度的一般情况。它已展开,因此每次迭代都执行两个* 4压缩整数= 32字节的输入数据。
add
和宏融合的
cmp/jb
,执行单元就无法跟上。每次迭代展开到4个
paddd
将为Sandybridge带来成功,并且可能也对Haswell有所帮助。
vpadd ymm1, [32+rsi]
,您可以获得两倍的吞吐量(如果数据在高速缓存中,否则仍然会成为内存瓶颈)。要对256b vector 进行水平求和,请从
vextracti128 xmm1, ymm0, 1
/
vpaddd xmm0, xmm0,xmm1
开始,然后与SSE情况相同。参见
this answer for more details about efficient shuffles for horizontal ops。
关于arrays - 遍历NASM中的阵列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31405072/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!