Linux程序集教程说明:
有一件非常重要的事情需要记住:如果您打算从程序返回(使用RET指令),请不要跳转到它!就像"从来没有!" 这样做会导致Linux上的分段错误(这是好的 - 所有程序都会终止),但在DOS中,它可能会因各种程度的可怕而在你脸上爆炸.
但我无法理解为什么它会导致分段错误.听起来就像从函数返回一样.
我有一种情况需要实现逻辑"如果X发生,请调用程序A.否则,调用程序B." 除了袋鼠编织意大利面条代码之外还有其他方式吗?
假设我有以下主循环
.L2:
vmulps ymm1, ymm2, [rdi+rax]
vaddps ymm1, ymm1, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
Run Code Online (Sandbox Code Playgroud)
我想时间的方式是把它放在另一个像这样的长循环中
;align 32
.L1:
mov rax, rcx
neg rax
align 32
.L2:
vmulps ymm1, ymm2, [rdi+rax]
vaddps ymm1, ymm1, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
sub r8d, 1 ; r8 contains a large integer
jnz .L1
Run Code Online (Sandbox Code Playgroud)
我发现的是我选择的对齐方式会对时序产生重大影响(最高可达+ -10%).我不清楚如何选择代码对齐方式.我可以想到三个地方,我可能想要对齐代码
triad_fma_asm_repeat下面的代码中).L1上面)重复我的主循环.L2上图). 我发现的另一件事是,如果我在源文件中放入另一个例程,即更改一条指令(例如删除指令),即使它们是独立函数,也会对下一个函数的时序产生重大影响.我甚至在过去看到过影响另一个目标文件中的例程.
我在Agner Fog的优化装配手册中阅读了第11.5节"代码对齐",但我仍然不清楚调整代码以测试性能的最佳方法.他给出了一个例子,11.5,计时内循环,我并没有真正遵循.
目前,从我的代码中获得最高性能是一种猜测不同值和对齐位置的游戏.
我想知道是否有一种智能方法可以选择对齐方式?我应该对齐内圈和外圈吗?只是内循环?该功能的入口?使用短期或长期NOP是否重要?
我最感兴趣的是Haswell,其次是SNB/IVB,然后是Core2.
我尝试了NASM和YASM,并发现这是一个显着不同的领域.NASM仅插入一个字节的NOP指令,其中YASM插入多字节NOP.例如,通过将上面的内部和外部循环对齐到32字节,NASM插入20条NOP(0x90)指令,其中YASM插入以下内容(来自objdump)
2c: 66 …Run Code Online (Sandbox Code Playgroud) 已解决的问题 应使主符号全局化,以便链接器在链接时可以在目标文件中找到它.更正了代码.
在执行任务时,尝试从程序集中调用简单的C函数(YASM汇编程序):
写了C函数:
#include <stdio.h>
void
func_in_c(char *s)
{
printf("%s", s);
}
Run Code Online (Sandbox Code Playgroud)
写了调用汇编代码:
segment .data
str_t_c db "Wow", 0
segment .text
global main ; That is the solution - let linker find global symbol
extern printf
extern func_in_c
main:
push rbp
mov rbp, rsp
lea rdi, [str_to_c]
call func_in_c
leave
ret
Run Code Online (Sandbox Code Playgroud)
汇编汇编:
yasm -f elf64 -m amd64 -g dwarf2 main.asm
Run Code Online (Sandbox Code Playgroud)
编译c代码:
gcc -o main_c.o -c main_c.c
Run Code Online (Sandbox Code Playgroud)
试图将两个目标文件链接到单个可执行二进制文件:
gcc -o main main_c.o main.o
Run Code Online (Sandbox Code Playgroud)
拿到:
...
In function _start:
(.text+0x20): undefined …Run Code Online (Sandbox Code Playgroud) 我想在C程序和要由nasm或yasm编译的程序集文件中包括很多魔术数字。
在纯C语言中,文件看起来像一系列定义,例如:
#define BLESS 55378008
#define ANSWER 42
...
Run Code Online (Sandbox Code Playgroud)
在nasm或yasm中,相同的include可以实现为:
%define BLESS 55378008
%define ANSWER 42
...
Run Code Online (Sandbox Code Playgroud)
唯一的不同是C和nasm 的define:前面的主角。#%
有什么办法可以编写一个polygot include,它可以让我将它同时包含在C和nasm中,并且只列出一次常量?
是的,我知道我可以使用sed或其他方法从另一个文件生成一个文件。
我已经在stackoverflow和其他制作手册,网站上搜索了很长时间,但找不到任何尾随空格或错过make函数中的用法.你能帮我解决这个警告信息吗?
make: Circular main.asm.o <- main.asm dependency dropped.
Run Code Online (Sandbox Code Playgroud)
Makefile文件:
AS:=yasm
CC:=gcc
OUTPUTDIR:=$(shell pwd)/bin
ASFLAGS:=-g dwarf2 -f elf64 -a x86
CFLAGS:=-g
SOURCES=$(wildcard *.asm)
OBJECTS=$(patsubst %.asm,%.o,$(SOURCES))
%.o: $(SOURCES)
$(AS) $(ASFLAGS) -o $(OUTPUTDIR)/$(OBJECTS) $<
all: $(OBJECTS)
$(CC) $(CFLAGS) -o httpd $(OUTPUTDIR)/$(OBJECTS)
clean:
rm $(OUTPUTDIR)/*
rm httpd
Run Code Online (Sandbox Code Playgroud)
main.asm中:
section .text
global main
extern exit
main:
mov rdi, 1
call exit
Run Code Online (Sandbox Code Playgroud)
谢谢 :)
例如,如果我有一个名为 test 的变量,声明如下:
test db 0x01 ;suppose the address is 0x00000052
Run Code Online (Sandbox Code Playgroud)
如果我做这样的事情:
mov rax, test ;rax = 0x00000052
mov rax, [test] ;rax = 0x01
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试保存它时,如果我们遵循相同的模式:
mov test, 0x01 ;address 0x00000052 = 0x01
mov [test], 0x01 ;address 0x01 = 0x01
Run Code Online (Sandbox Code Playgroud)
但实际上是:
mov [test], 0x01 ;address 0x00000052 = 0x01
Run Code Online (Sandbox Code Playgroud)
那么,为什么方括号的行为取决于它们是第一个还是第二个操作数?
我的问题是,“我有新的 yasm,我认为 x264 应该很酷,为什么 x264 不酷?”
出于某些原因,我正在按照指南构建一个 CentOS docker 镜像(基于 centos:latest),其中包含一个从头开始构建的 ffmpeg 此处。这是一个很好的指南,它以前对我有用,所以我感觉很好。
今天我遇到了 libx264 构建点的瓶颈:具体来说,我说
PKG_CONFIG_PATH="/tmp/ffmpeg_build/lib/pkgconfig" \
./configure \
--prefix="/tmp/ffmpeg_build" \
--bindir="/tmp/bin" \
--enable-static
Run Code Online (Sandbox Code Playgroud)
我得到回复
找不到汇编程序
最低版本为 nasm-2.13
如果你真的想在没有 asm 的情况下进行编译,请使用 --disable-asm 进行配置。
这是出乎意料的。我有 yasm,我理解它是 1) 在那里做 nasm 做的事情,但更好,2) 成为雏菊新鲜的最现代版本,因为我大约一个小时前从它的 repo 中取出它,并构建它五十九分钟前。就其价值而言,nasm 也在盒子上,因为说明要求它,但它低于其规定的版本(即“NASM 版本 2.10.07 编译于 2014 年 6 月 9 日”)
所以似乎没有找到 yasm 。还有另一个StackExchange question提到了这个问题,这是一个路径问题。因此,我将 yasm 添加到我的路径中,如下所示:
PATH=/tmp/ffmpeg_sources/yasm:$PATH \
PKG_CONFIG_PATH="/tmp/ffmpeg_build/lib/pkgconfig" \
./configure
...etc
Run Code Online (Sandbox Code Playgroud)
这仍然会导致 Found-no-assembler 问题。作为最后一个令人困惑的方法,我明确地告诉脚本我想对变量 $AS 使用什么,因为根据我对 configure 的快速查看,这看起来像是 yasm/nasm 应该去的地方。命令变为:
AS=`which yasm`
PKG_CONFIG_PATH="/tmp/ffmpeg_build/lib/pkgconfig" …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 yasm 汇编下面的代码。我在 yasm 报告错误“错误:操作数 2 的大小无效”的地方添加了“此处”注释。为什么会发生这个错误?
segment .data
a db 25
b dw 0xffff
c dd 3456
d dq -14
segment .bss
res resq 1
segment .text
global _start
_start:
movsx rax, [a] ; here
movsx rbx, [b] ; here
movsxd rcx, [c] ; here
mov rdx, [d]
add rcx, rdx
add rbx, rcx
add rax, rbx
mov [res], rax
ret
Run Code Online (Sandbox Code Playgroud) 我需要获得以下输出:
*
**
***
****
*****
******
*******
********
*********
**********
Run Code Online (Sandbox Code Playgroud)
所以它的10行,而我的星星将从1开始到10。
目前我得到:
**********
***********
************
*************
**************
***************
****************
*****************
******************
*******************
********************
Run Code Online (Sandbox Code Playgroud)
我的代码:
*
**
***
****
*****
******
*******
********
*********
**********
Run Code Online (Sandbox Code Playgroud)
我尝试了又尝试了又尝试了,但是我无法获得所需的东西。
由于所有这些push和,我似乎无法找到一种将行与星线分开的方法pop。
老实说,我对此不太了解。有人告诉我,执行循环需要它们,但是我不确定为什么要在函数star中调用外部循环。
我找不到任何的组合push和pop奏效。我不断得到很多星,或者每行一颗星,或者只有一颗星。
我真的不知道要更改哪些位并保持不变。我能够获得所需的输出,但是输出从未停止增加。
我能够得到从10颗星开始下降到1颗星的输出,但是从来没有我想要的。
我究竟做错了什么?我该怎么办?
我试图让 yasm 输出一个 16 位近相对 jmp。具体来说,它将是带有操作数大小覆盖前缀的 rel16/rel32 jmp 操作码。我知道jmp short labelwill 发出一个 8 位近相对 jmp,ajmp long label将发出一个 32 位近相对 jmp,但如何让它发出 16 位近相对 jmp?
具体来说我正在使用bits 32和cpu i686