X



アセンブラ初心者スレッド 2©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
0003デフォルトの名無しさん
垢版 |
2017/04/13(木) 18:14:24.24ID:VLmLig3K
v3
0005デフォルトの名無しさん
垢版 |
2017/04/13(木) 18:15:32.34ID:VLmLig3K
終了
0006 ◆QZaw55cn4c
垢版 |
2017/04/13(木) 19:36:20.78ID:RYqONwMZ
きょうびの時代にアセンブラの優位性を主張する,とすれば
どのような分野で有効でしょうか?
0007デフォルトの名無しさん
垢版 |
2017/04/13(木) 19:43:03.43ID:VLmLig3K
asm.js とかさ
LLVM とかさ
このスレで扱っても良いと思うのね
0012デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:12:03.81ID:2Mj3RTtW
アセンブラはじめるならLinuxでやるといいよ
DOSと同じような感覚でアセンブラプログラミングができるから

こんな感じ

Linux でアセンブリプログラミング
http://www.mztn.org/lxasm/asm00.html
Linux で64bitアセンブリプログラミング
http://www.mztn.org/lxasm64/amd00.html

Linuxでのアセンブル方法はこんな感じ
as -a=hogehoge.lst -o hogehoge.o hogehoge.s
ld -o hogehoge hogehoge.s

gccのでアセンブラ出力&アセンブル
gcc -S -o hogehoge.s hogehoge.c
as -a=hogehoge.lst -o hogehoge.o hogehoge.s
gcc -o hogehoge hogehoge.o
0013デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:12:41.23ID:2Mj3RTtW
ちなみにx86_64上のLinuxで32bitのバイナリを作成したい場合はこう


x86_64のLinuxでのCの32bitのx86バイナリのコンパイル
gcc -m32 -O2 -o hogehoge hogehoge.c

x86_64のLinuxでの32bitのx86アセンブル
as --32 -a=hogehoge.lst -o hogehoge.o hogehoge.s
ld -melf_i386 -o hogehoge hogehoge.o

x86_64のLinuxでのgccので32bitアセンブラ出力&アセンブル
gcc -m32 -S -o hogehoge.s hogehoge.c
as --32 -a=hogehoge.lst -o hogehoge.o hogehoge.s
gcc -m32 -o hogehoge hogehoge.o
0014デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:13:21.76ID:2Mj3RTtW
nasmでのx86_64のLinuxでの32bitアセンブル

nasm -f elf hogehoge.s
ld -melf_i386 -o hogehoge hogehoge.o


nasmでのx86_64のLinuxでの64bitアセンブル
nasm -f elf64 $1.s
ld -o $1 $1.o


Ubuntuでのnasmのインストール方法

sudo apt-get install nasm
0015デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:42:00.93ID:2Mj3RTtW
UbuntuだとQEMUを入れるだけでQEMU+binfmtの設定が自動せされるから
ライブラリへのリンクを貼るだけで他のCPUのバイナリをそのまま実行できるようになる
UbuntuだとARM、MIPS、PowerPCができる

64bitARMならこんな感じ
sudo apt-get install qemu
sudo apt-get install g++-aarch64-linux-gnu
sudo ln -s /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 /lib
sudo ln -s /usr/aarch64-linux-gnu/lib /lib/aarch64-linux-gnu

32bitARMならこんな感じ
sudo apt-get install qemu
sudo apt-get install g++-arm-linux-gnueabihf
sudo ln -s /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 /lib
sudo ln -s /usr/arm-linux-gnueabihf/lib /lib/arm-linux-gnueabihf

Cのコンパイル方法はこんな感じ
aarch64-linux-gnu-gcc -O2 -o hogehoge hogehoge.c

arm-linux-gnueabihf-gcc -O2 -o hogehoge hogehoge.c

数学ライブラリを使う場合のCのコンパイル方法はこんな感じ
aarch64-linux-gnu-gcc -O2 -o hogehoge hogehoge.c -lm
(Ubuntuでは依存するライブラリを後ろに書く)

arm-linux-gnueabihf-gcc -O2 -o hogehoge hogehoge.c -lm
0016デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:43:20.47ID:2Mj3RTtW
アセンブル方法はこんな感じ
aarch64-linux-gnu-as -a=hogehoge.lst -o hogehoge.o hogehoge.s
aarch64-linux-gnu-ld -o hogehoge hogehoge.s

arm-linux-gnueabihf-as -a=hogehoge.lst -o hogehoge.o hogehoge.s
arm-linux-gnueabihf-ld -o hogehoge hogehoge.s

アセンブラソースの出力はこんな感じ
aarch64-linux-gnu-gcc -S -o hogehoge.s hogehoge.c
aarch64-linux-gnu-as -a=hogehoge.lst -o hogehoge.o hogehoge.s
aarch64-linux-gnu-gcc -o hogehoge hogehoge.o

arm-linux-gnueabihf-gcc -S -o hogehoge.s hogehoge.c
arm-linux-gnueabihf-as -a=hogehoge.lst -o hogehoge.o hogehoge.s
arm-linux-gnueabihf-gcc -o hogehoge hogehoge.o


できたバイナリは普通に実行できる
./hogehoge
バイナリがどのアーキテクチャかはfileコマンドで確認できる
file hogehoge
0017デフォルトの名無しさん
垢版 |
2017/04/15(土) 04:44:00.98ID:2Mj3RTtW
32bitのARMでUbuntuのgnueabihfではデフォルトでThumb-2でコンパイルされる
ARM命令でコンパイルする場合はオプションを追加する

ARM命令の場合の例
-marm -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16
-marm -march=armv7-a -mfloat-abi=hard -mfpu=neon -ffast-math

実行例)
arm-linux-gnueabihf-gcc -O2 -marm -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -o hogehoge hogehoge.c

arm-linux-gnueabihf-gcc -O2 -S -marm -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -o hogehoge.s hogehoge.c
arm-linux-gnueabihf-as -a=hogehoge.lst -o hogehoge.o hogehoge.s
arm-linux-gnueabihf-gcc -marm -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -o hogehoge hogehoge.o

参考)
Thumb-2命令の場合の例
-mthumb -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16
-mthumb -march=armv7-a -mfloat-abi=hard -mfpu=neon -ffast-math
0020デフォルトの名無しさん
垢版 |
2017/04/15(土) 08:02:58.82ID:2Mj3RTtW
補足
32bitARMでのシステムコールの呼び出しはEABIの方式で行ってください

.text
.align 2
.global _start
_start:
adr r1, msg @ address
mov r0, #1 @ stdout
mov r2, #13 @ length
mov r7, #4 @ sys_write
swi 0

mov r0, #0
mov r7, #1 @ sys_exit
swi 0

.align 2
msg:
.asciz "hello, world\n"
0021デフォルトの名無しさん
垢版 |
2017/04/15(土) 08:35:58.99ID:2Mj3RTtW
32bitARMでFPU命令を使う場合の例
arm-linux-gnueabihf-as -mfpu=vfpv2 -a=hogehoge.lst -o hogehoge.o hogehoge.s
arm-linux-gnueabihf-as -mfpu=vfpv3-d16 -a=hogehoge.lst -o hogehoge.o hogehoge.s
0022デフォルトの名無しさん
垢版 |
2017/05/07(日) 22:56:59.24ID:8v4hzv7f
Intel AVX512とか32ビットモードや16ビットモードでマシン語記述できるの?
16ビットモード(MS−DOS6.2)で32ビット命令を実行できることは確認ずみ。
0023デフォルトの名無しさん
垢版 |
2017/05/08(月) 01:10:33.28ID:UxHus5NQ
どうやってマシン語生成するつもりか分からんが、マシン語は記述できるだろ。
0025デフォルトの名無しさん
垢版 |
2017/05/09(火) 04:41:32.11ID:CfLPAbNS
いまじゃ解析とか簡単になっとるからなぁ
小学生でもできるんじゃない?
0028デフォルトの名無しさん
垢版 |
2017/07/19(水) 15:57:14.47ID:4WYjcaP8
>>22
理屈の上ではアセンブラがそれらの命令をサポートしてれば可能。
ただ、今はアセンブラの方がMS-DOSサポートして無いだろうからクロス開発になりそう。
(動けば運が良かったって程度)

でもリアルモードでバイト数大きい64bit命令使うメリットは無い希ガス。
せめてプロテクトモードに移行してから64bit命令使った方が。。。
と言うか、Linuxのブートローダーからロングモード移行までの記事最近読んだけど、アセンブラから見たら多分16bit32bitじゃ無くてリアルモードかプロテクトモードかのが重要(使えるメモリの大きさが違う)な希ガス。

http://postd.cc/linux-bootstrap-1/
0029デフォルトの名無しさん
垢版 |
2017/10/19(木) 07:34:02.07ID:5IzztSYd
TLCS-900H2のDL命令の意味を教えてください
ソースを見る限りではCALLと同等のようですが
0033デフォルトの名無しさん
垢版 |
2018/02/21(水) 13:16:23.71ID:VklNYIB8
初心者質問じゃないのだが、調べてもわからないので知ってる人がいたら教えて欲しい

Zynqを使ってハードウェアエミュレータを作ろうとしているんだが、
そのままだとアドレス0x40000000からしか自由に使えなくて困ってるんだけども、
Cortex-A9のMMUを設定するにはどうしたらいいんだろうか?
やりたいことはアドレス0x40000000から0x4FFFFFFFまでを0x00000000から0x0FFFFFFFにマッピングしたい
0034デフォルトの名無しさん
垢版 |
2018/02/22(木) 03:37:57.63ID:hXyx6D5H
>>33
MMUについてどれだけ知っているのか分からないが
とりあえずLinuxのARMv7周りのコードを調べるのがよいと思われ
"linux arm source mmu"辺りをググッてみるとか
あとはARMのリファレンスマニュアル
http://infocenter.arm.com/help/index.jsp
から、「ARM アーキテクチャ」→「Reference Manuals」→「ARM アーキテクチャ リファレンス マニュアル ARMv7-A および ARMv7-R エディション」
のPDF、1267ページ以降を参照

大まかな手順としては
・ページテーブルを構築
・変換テーブルベースレジスタ(TTBR0、TTBR1)をセット
・変換テーブルベース制御レジスタ(TTBCR)をセット
・システム制御レジスタ(CP15 c1、SCTLR)レジスタのMMU有効化ビットをON
となると思われ
0035デフォルトの名無しさん
垢版 |
2018/02/23(金) 00:45:14.45ID:ulmXMJQn
>>34
ありがとう
linuxカーネルを参考にしてやってみる
0036デフォルトの名無しさん
垢版 |
2018/02/24(土) 13:07:22.87ID:tiS2olHY
>>34
armのドキュメント読みつつzynqでステップ実行しながらメモリの状態見てみたんだが、
以下の認識で合ってるだろうか?
・ページテーブルを構築
  適当なメモリ領域にページテーブルを構築(要16kiBアラインメント)
  (レジスタをいじって設定とかではなく例えば0x80000000番地に作っておく等)
・変換テーブルベースレジスタ(TTBR0、TTBR1)をセット
  TTBR0はユーザー用、TTBR1はOS用
  さっき用意したページテーブルの先頭アドレス(上位ビット)を渡す
  下位ビットの方にその他の設定する
・システム制御レジスタ(CP15 c1、SCTLR)レジスタのMMU有効化ビットをON
  SCTLRのBit0に1をセット
0037デフォルトの名無しさん
垢版 |
2018/02/24(土) 18:39:17.01ID:B8xdCHC7
>>36
俺はARMはちゃんと触ってないので確実なことは言えないが
基本的にはそれで合っていると思う

ページテーブルとTTBRは物理アドレス(PA)で管理、ページテーブル内は仮想アドレス(VA)とPAの対応関係にアクセス保護ビット等
ページテーブルが2段以上(ページディレクトリ経由)になる場合はページディレクトリ内のデータの解釈が少し変わる

RISC系CPUはTLBミスヒットした時のテーブルウォークを自前で叩いてやらないといけない場合があったが、ARMv7ではCPUが自動でやる模様
あと微妙にキャッシュの管理とMMU周りの管理が絡み合っているようで、ここを俺は把握し切れていない

とにかく、Cortex-Aではコプロセッサ#15(CP15)がMMUなので、CP15の制御レジスタ周りをよく見ておいたほうがよいと思われ
0038デフォルトの名無しさん
垢版 |
2018/02/25(日) 15:07:04.60ID:EC94jTzS
>>37
0x40000000の内容に0x00000000からアクセスできるようになった!
GBA(ARM7TDMI)のBIOSもちゃんと実行できてるっぽい
VRAM領域にアクセスしに行って止まってるが(;・∀・)
TLBのattributeの設定はとりあえず適当だが動いてるしよくわからんけど放置しよう・・・
0040デフォルトの名無しさん
垢版 |
2018/02/26(月) 06:57:20.16ID:SxohJEGp
気楽にx86_64のアセンブラをやりたい人はこれを読むといいかもね
ただ、あまり詳しくは書かれてない
あくまで、初心者がx86_64アセンブラのとっかかりを掴むために読む本
CPUについての詳しい解説はあまり書かれてない(レジスタの解説程度)
x86_64のWindowsアセンブラ特有のスタックの使い方についても簡単に解説されてる
(x86_64のWindowsのアセンブラではスタック操作を自由にやってはいけない)
この本を読むとx86_64のアセンブラを簡単に試せるようになる

64ビットアセンブラ入門―64ビットCPUの基本構造もやさしく解説
https://www.amazon.co.jp/dp/4877833617/
0041デフォルトの名無しさん
垢版 |
2018/02/26(月) 15:57:09.08ID:SxohJEGp
x86_64のWindowsのアセンブラで最初に嵌るのがスタック関係

ttp://herumi.in.coocan.jp/prog/x64.html
Windowsでのスタック
スタックは常に16byteアラインメントされています.
ただし関数呼び出し直後は戻りアドレス(8byte)がpushされているため, 8(mod 16)となっています.
関数内から別の関数を呼び出すときはアライメントを揃える必要があり,
引数4個のスタック分(32byte)を呼び出し元で確保する必要があります.
確保された領域は呼び出された側で自由に使えます.

Windowsでのスタックの扱い方はここのページを参照するといいかも
ttp://www.officedaytime.com/tips/asm64/caution.html
x64アセンブラ関数の書き方の注意【すごく要注意】
スタックが自由に使えない
32ビットまでのインラインアセンブラでは好き勝手にpush/popしたりして使えていたスタックが
x64では厳しい使用制限を受けることになりました。

具体的には以下のような制限です。
スタックポインタが動くような操作をしていいのは関数の最初と最後の部分だけ
(フレームポインタ(後述)を設定しない場合)。
その部分は「prolog」「epilog」と呼ばれ、やっていいことが決まっている。
prologが終わった時点でスタックポインタは16の倍数になっていなければならない
(中から他の関数を呼ばない場合はこの制限はない)。

ただし、push/popやその他の方法でRSPを動かさない、
何も呼び出さない、
壊してはいけないレジスタをセーブ(push/popに限らずいかなる方法でも)しない、
例外処理をしない、
のすべての条件を満たす関数は「leaf」(関数呼び出しツリーの枝の末端の葉っぱ、くらいの意味でしょうか)と呼ばれ、
この制限を受けません。
前ページのコーディング例にprolog/epilogがないのはそのためです。
-------以下、prolog/epilogの方法はページを参照-------
0042デフォルトの名無しさん
垢版 |
2018/02/28(水) 14:26:24.02ID:S610+cRR
アライメントとアラインメントとか
用語もちゃんと揃えて欲しいな
0043デフォルトの名無しさん
垢版 |
2018/03/08(木) 20:28:48.99ID:uhDvi+9f
linuxでのx86_64のコンパイル&アセンブル


コンパイル
gcc -O2 -o hogehoge hogehoge.c

コンパイルでアセンブル出力&アセンブル&リンク
gcc -O2 -S -masm=intel -o hogehoge.s hogehoge.c
as -a=hogehoge.lst -o hogehoge.o hogehoge.s
gcc -o hogehoge hogehoge.o

  注:gccに-Sオプションを付けた場合に-masm=intelオプションを付けるとInteニーモニックのアセンブルリストが出力される
     (デフォルトではAT&Tニーモニックで出力される)


アセンブル&リンク
as -a=hogehoge.lst -o hogehoge.o hogehoge.s
ld -o hogehoge hogehoge.o

  注:アセンブラソースに.intel_syntax noprefixを記述するとgasでIntelニーモニックを使えるようになる
     (デフォルトではAT&Tニーモニック)
0044デフォルトの名無しさん
垢版 |
2018/03/08(木) 20:29:33.06ID:uhDvi+9f
例) Linuxアセンブラ版hello world

.intel_syntax noprefix
.text
.global _start
.align 4
_start:
mov rax, 1 # sys_write (1)
mov rdi, 1 # stdout (1)
movabs rsi, offset flat: msg # address(offsetを付けることによってアドレスをロードする)
# gasでは64bitイミディエイトや64bit絶対アドレス指定でのメモリからのロードを使う場合はmovabsを使う
mov rdx, offset flat: len # length(offsetを付けることによってアドレスをロードする)
syscall
mov rax, 60 # exit (60)
xor rdi, rdi # return 0
syscall
.data
.align 8
msg:
.asciz "hello, world\n"
.equ len, . - msg
.end
0045デフォルトの名無しさん
垢版 |
2018/03/08(木) 20:32:10.43ID:uhDvi+9f
64bitLinuxでの32bit x86のコンパイル&アセンブル


コンパイル
gcc -O2 -m32 -o hogehoge hogehoge.c


コンパイルでアセンブル出力&アセンブル&リンク
gcc -O2 -S -m32 -masm=intel -o hogehoge.s hogehoge.c
as -a=hogehoge.lst --32 -o hogehoge.o hogehoge.s
gcc -m32 -o hogehoge hogehoge.o


アセンブル&リンク
as -a=hogehoge.lst --32 -o hogehoge.o hogehoge.s
ld -melf_i386 -o hogehoge hogehoge.o
0046デフォルトの名無しさん
垢版 |
2018/03/08(木) 20:34:16.87ID:uhDvi+9f
例) Linuxアセンブラ版hello world(32bit)
.intel_syntax noprefix
.text
.global _start
.align 4
_start:
mov eax, 4 # sys_write (4)
mov ebx, 1 # stdout (1)
mov ecx, offset msg # address(offsetを付けることによってアドレスをロードする)
mov edx, offset len # length(offsetを付けることによってアドレスをロードする)
int 0x80
mov eax, 1 # exit (1)
xor ebx, ebx # return 0
int 0x80
.data
.align 4
msg:
.asciz "hello, world\n"
.equ len, . - msg
.end
0047デフォルトの名無しさん
垢版 |
2018/03/10(土) 06:44:54.80ID:L0iyZELB
あせんぶりゃー
あせんぶり
あせんぶる
0048デフォルトの名無しさん
垢版 |
2018/03/11(日) 17:22:40.99ID:lDE3fY11
x86_64のリファレンスマニュアル

インテルR エクステンデッド・メモリー 64 テクノロジー・ソフトウェア・デベロッパーズ・ガイド、第 1 巻
https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/EM64T_VOL1_30083402_i.pdf

インテルR エクステンデッド・メモリー 64 テクノロジー・ソフトウェア・デベロッパーズ・ガイド、第 2 巻
https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/EM64T_VOL2_30083502_i.pdf
0051デフォルトの名無しさん
垢版 |
2018/05/03(木) 11:38:07.04ID:83GzP0HZ
違った

相対ジャンプは、ほぼ全てが相対ジャンプだから、86からあるな
386からは、8bit限定じゃなくなったのは、条件ジャンブだ
0052デフォルトの名無しさん
垢版 |
2018/05/03(木) 12:21:57.39ID:0pg5Dj/G
うんまあそういう感じで多分勘違いしていた
というかワード幅のは絶対ジャンプといつのまにか思ってたらしい...(*ノノ)
0053デフォルトの名無しさん
垢版 |
2018/05/03(木) 13:31:52.82ID:bkPu29QU
Hugeモデルω
0054デフォルトの名無しさん
垢版 |
2018/05/23(水) 19:33:19.00ID:Au5e7VGg
僕の知り合いの知り合いができたパソコン一台でお金持ちになれるやり方
役に立つかもしれません
グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』

Z4DKB
0057デフォルトの名無しさん
垢版 |
2018/06/13(水) 15:38:35.51ID:lSIEjw1a
その昔条件分岐のオフセットが8ビットを超えると勝手にnear分岐に展開してくれるアセンブラがあってだな
0058デフォルトの名無しさん
垢版 |
2018/06/13(水) 15:56:44.91ID:mbrmHeFX
で?
0060デフォルトの名無しさん
垢版 |
2018/07/04(水) 22:19:45.76ID:gFgZc5FG
TDC
0063デフォルトの名無しさん
垢版 |
2018/07/21(土) 10:03:59.76ID:JzufiDOi
Julia
0064デフォルトの名無しさん
垢版 |
2018/07/31(火) 18:07:47.27ID:K5ZjI7P1
初心者なので意味が解らないんだけど、オブジェクト指向って考え方なんじゃないの?
0065デフォルトの名無しさん
垢版 |
2018/07/31(火) 23:36:25.25ID:M9aZq/V8
ところで、2つの32BIT レジスタの値を、64BITレジスタの上位32bit、下位32bit に
分けて入れる場合、shld を使えばいいのかな?

32BIT 時代の場合は、ebx <--- dx:ax としたい場合、

mov bx,dx
shl ebx,16
mov bx,ax

などとしたもんだけど、64BIT モードで、rbx <--- edx:eax としたい場合、
例えば、

shld rdx,rax,32
mov rbx,rbx

とするのかな。
0067デフォルトの名無しさん
垢版 |
2018/07/31(火) 23:39:52.06ID:M9aZq/V8
もしかして、mmx レジスタや xmm レジスタの、shuffle 命令なども使えたりする
のだろうか??
0069デフォルトの名無しさん
垢版 |
2018/07/31(火) 23:51:35.80ID:PrQlt9wc
>>68
もちつけ
0072デフォルトの名無しさん
垢版 |
2018/07/31(火) 23:58:34.01ID:M9aZq/V8
なるほど、つまり:

shl rdx, 32
mov ebx, eax
or rbx, rdx

と。OR を使うとは全く思いつかなかった。
0074デフォルトの名無しさん
垢版 |
2018/08/01(水) 00:02:01.85ID:s+zy6Um6
もちつけ
0075デフォルトの名無しさん
垢版 |
2018/08/01(水) 00:17:55.42ID:M1fpQAcB
【まとめ】

64BIT モードでは、mov 命令などの destination が、32BITレジスタの場合、
原則的に、対応する64BITレジスタの上位32BITがゼロクリアされてしまうの
で注意が必要。蛇足だが、destinationが16BITレジスタや8BITレジスタの
場合は、対応する64BITレジスタの残りの上位ビットは完全に保持される。

この結果、2つの同じビット数のレジスタを2倍のビット数のレジスタの上位、下位
に代入したい場合、

32BIT Legacy Mode で、ebx <--- dx:ax としたい場合、

mov bx,dx
shl ebx,16
mov bx,ax    ;ebx(64BITモードだと、rbx) の上位16ビット(上位48BIT)は、
          ;直前のまま変化しない。

で良かったが、

64BIT モードで、rbx <--- edx:eax としたい場合、

shl rdx, 32    ; 左シフトの結果、rdx の下位32BIT は、0になる。
mov ebx, eax  ; rbx の上位32BIT は(勝手に)0クリアされる。
or rbx, rdx

や、

shl rax,32     ; 左シフトの結果、rax の上位32BITに元の eaxが入る事になる。
shld rdx,rax,32  ; rdx : rax をひとまとめにして 32BIT分、左シフト。
mov rbx,rdx

などとする必要がある。
0076デフォルトの名無しさん
垢版 |
2018/08/01(水) 00:48:03.95ID:hfBYO5dB
64bitレジスタの上位が0になるのは無駄な依存関係を無くすため

32bitレジスタの部分書き換えは大きなペナルティが発生するので注意
0077デフォルトの名無しさん
垢版 |
2018/08/01(水) 00:52:48.93ID:hfBYO5dB
アセンブラで高速なコードを書くなら
インテルの最適化マニュアルを一通り読むことを勧める
IACAも非常に便利
0078デフォルトの名無しさん
垢版 |
2018/08/01(水) 20:01:51.01ID:UPXl5ngF
アセンブラは普通に書いただけでもCに比べてバイナリも非常に小さいし高速に動いてくれるよね
0079デフォルトの名無しさん
垢版 |
2018/08/01(水) 23:09:30.00ID:iFKJPY0w
ペナルティを避けるため、普通は同じレジスタでも別のでもいいから、movzx使って上位ビットが0だって明示してから使うべき
0080デフォルトの名無しさん
垢版 |
2018/08/01(水) 23:17:32.46ID:iFKJPY0w
今回の64ビットバージョンのrbx <--- edx:eax としたい場合は関係なかったけど、
mov bx,dxをやった後にebxやrbxを参照するとペナルティが発生するのは32ビットでも一緒だけどね
0084デフォルトの名無しさん
垢版 |
2018/08/02(木) 23:06:24.79ID:vIaAZbox
>>79
確か、64BIT モードだと、そもそも、movzx reg64,reg32 に相当する専用命令が
存在せず、その代わりに、単なる mov reg32,reg32 を使う想定になっているはず。
なぜなら、後者でも上位32BITが0になるから。

一方、movsx reg64,reg32 については、新しい新命令として、movsxd なる
ものが導入されている。なぜなら、movsx の第二オペランドは、32BIT時代
から、8BIT か、16BIT レジスタしか採りえないから。命令自体で
第二オペランドのビット数が固定されていて、第二オペランドが
8BIT と 16BIT で別々の opcode になっていて、0x66 prefix でデータサイズ
を変えた場合は、第一オペランドのサイズが変わるだけ、という仕様だった
から。つまり、64BITモードでも、第二オペランドのBIT数は、
opcode 自体で固定されてしまっているので、REX.W や 0x66 prefix では
第二オペランドのBIT数の変更はされない、というのが素直な解釈だったから。
0085デフォルトの名無しさん
垢版 |
2018/08/11(土) 19:53:27.03ID:Pi7uIeu1
[test3.asm]
.data
my_mojiretu  db 'somothing', 0   ;1
.code
    mov   rax,offset my_mojiretu   ;2
    xor    rbx,rbx
    mov   al,my_mojiretu[rbx]    ;3
-------------------------------------------------------------------
2 は、大丈夫なのに、3 だと、以下のようなエラーになる。なぜ?
test3.obj に「絶対アドレス」の relocation 情報が入ることにはなるハズなんだけど。

J:\Develop\C\masm64_s\masm64>d:\ml64\bin\ml64.exe /Fl test3.asm /link /libpath:"
C:\Program Files (x86)\Windows Kits\8.0\Lib\win8\um\x64" /subsystem:windows /def
aultlib:kernel32.lib /defaultlib:user32.lib /entry:main
Microsoft (R) Macro Assembler (x64) Version 9.00.30729.207
Copyright (C) Microsoft Corporation. All rights reserved.

Assembling: test3.asm
Microsoft (R) Incremental Linker Version 9.00.30729.207
Copyright (C) Microsoft Corporation. All rights reserved.

/OUT:test3.exe
test3.obj
"/libpath:C:\Program Files (x86)\Windows Kits\8.0\Lib\win8\um\x64"
/subsystem:windows
/defaultlib:kernel32.lib
/defaultlib:user32.lib
/entry:main
test3.obj : error LNK2017: 'ADDR32' relocation to 'my_title' invalid without /LA
RGEADDRESSAWARE:NO
LINK : fatal error LNK1165: link failed because of fixup errors
0086デフォルトの名無しさん
垢版 |
2018/08/11(土) 19:55:58.66ID:Pi7uIeu1
エラーでは、my_title になってるけど、5ch に登校する際に、
ソースを my_mojiretu に変えただけなので、同じと思って。

あと、somothing は、something の typo。
0087デフォルトの名無しさん
垢版 |
2018/08/11(土) 20:05:28.32ID:Pi7uIeu1
あー。例外的に2の部分の、
mov reg,imm
は、imm に 64BIT 即値が入れられるけど、3の部分では、
ModRMの間接参照の
[ebx + disp]
を使ってるけど、この形では、dispに32BIT までしか入れられないからだな。。。
なるほど。つまり、
mov al,my_mojioretu[ebx]
は、
mov al,[ebx + disp64]
としたくても、AMD64 ではそのようなメモリオペランドが使えないので、
mov al,[ebx + disp32]
にしかアセンブルできないと。

だから、絶対アドレスが、32BIT を超えるような値になった場合にはどうしようも
ないと。
0089デフォルトの名無しさん
垢版 |
2018/08/11(土) 22:13:23.67ID:QecvtyFY
>>85
実際に試してないから推測だけど、2では64bitレジスタに代入しているのに対して
3では8bitレジスタALに代入しようとしている。EAXかRAXに代入してみれば動くんではないかと。
0091デフォルトの名無しさん
垢版 |
2018/08/12(日) 06:49:59.09ID:kb51JNcZ
AMD64 では、ModRM を使った MemoryOperand の [reg64 + disp] のような形式の場合、
disp の BIT 数が、最大でも、
 [reg64 + disp32]
のように 32BIT までが限界で、64BIT の disp64 は存在していない。
imm も「一般的には」、imm32 までで、imm64 は使えない。
ところが、mov reg,imm に関しては、例外的に
 mov reg64, imm64
という命令が存在している。また、似た話として、
ModRM を使わない MemoryOperand では、disp64 のようなものが例外的に
存在していて、
 mov reg,[disp64]
というものが存在している。ただし、意味的には、[disp64] ではなく、[moffset64]
のような意味合いで、
 mov reg,[moffset64] や
 mov reg,moffset64
と書かれることがある。この場合、[] が付いてなくても意味は同じ(混乱注意)。
ちなみに、mem64 は、データサイズが 64BIT という意味なので、
 qword ptr [xxxx]
の意味になるので、また違う。

つまり、レジスタに入れてアクセスできるアドレスは64BITなのに、固定アドレスを入れてアクセス
できるメモリは、32BIT に制限されやすい、ということ。ただし、上記のような例外が用意されている
ので、絶対に32BITを超えた固定アドレスのメモリをアクセスできないというわけではない。
0092デフォルトの名無しさん
垢版 |
2018/08/12(日) 06:59:38.95ID:kb51JNcZ
ちなみに、
.data
ラベル名 db 'xxxx',0  ;1
.code
lea ebx,ラベル名   ;2
のような場合、一見、2の第二オペランドは、ModRM に encode されるので、
lea ebx,[disp32]
になってしまうから、この場合も、32BIT の限界に遭遇してしまうのではないかと
思ってしまうかもしれない。ところが、実際には、
lea ebx,[rip + rel_addr32]
のように命令ポインタの rip 相対のアドレスとして、encode されるので、また、事情が
違ってくる。結論的には、この場合は、ラベル名がリンクに指定した obj の中にある
限りにおいては、32BIT の限界を特に気にすることは無い。
0093デフォルトの名無しさん
垢版 |
2018/08/12(日) 07:04:02.85ID:kb51JNcZ
>>92
間違った。 ebx ではなく、rbx だった:

lea rbx,ラベル名   ;2
lea rbx,[disp32]
lea rbx,[rip + rel_addr32]
0094デフォルトの名無しさん
垢版 |
2018/08/16(木) 12:39:22.96ID:ZqqdGQwm
>>41
実は、以下のようにしておくだけで、SEH例外のサポートも含めて、
ほぼ、push, pop は自由に出来るようになるらしい。

1. 関数の最初と最後を以下のように書く :
push rbp
mov rbp, rsp
・・・
pop rbp
ret

2. rbp を frame pointer に使っているということを、関数の prolog に書く。

【「ほぼ」 の例外】

call 関数名などの関数コールの直前では、rsp を16バイトアラインしてある
必要があること。それさえ気をつけていれば、push, pop は自由に行える。

【16倍とスタックアラインについて】

push rbp のおかげで、return address の 8 バイトと合わせて、直後からは、
上手く勝手に rsp が 16 バイトにアラインされた状態になってくれる。
だから、余り難しい事を考える必要は無い。
0095デフォルトの名無しさん
垢版 |
2018/08/16(木) 13:12:50.69ID:ZqqdGQwm
frame pointer(rbp) を使わない場合は、関数の通常部分では、rsp を最初から最後まで
固定しなくては、構造化例外を処理出来なくなる。

なので、rsp が変化する事になる push, pop が使えなくなる。

(なお、人間にとっては便利でも、コンパイラにとっては、元々 push, pop は使いにくい
命令であった。)

x86、x64 アーキテクチャでは、mov reg, reg/mem のような事は出来ても、
mov mem, mem は出来ない。ところが、この、push, pop についてはそれが
出来てしまう数少ない例外。

例えば、

push qword ptr [ebp + disp1]  ;1

push qword ptr [esp + disp1]  ;2

で、ローカルの auto 変数をスタックに保存する事が出来る。ところが、

mov qwrod ptr [esp + disp1], qword ptr [esp + disp2]  ;3

とは出来ない。だから、push 命令を使うと、実はパフォーマンスが向上する可能性も
秘めてはいるかも知れない。ただし、これも、レジスタの個数が十分沢山ある
近年では、必ずしもそうとも言えないかもしれない。レジスタの個数が不足して
スタックに保存したくなった場合、

mov [esp + disp1], reg  ;4

と書けばいいわけであって、3 のように書く必要性は、近年では下がっているようだから。
0096デフォルトの名無しさん
垢版 |
2018/08/16(木) 13:27:50.54ID:ZqqdGQwm
>>95
誤:esp, ebp
正:rsp, rbp


【なぜ、3の必要性が少ないかについて】

3のようにしなくても、そもそも、3の第二オペランドの値は、メモリ上において
あるのだから、レジスタが不足しても値が消えてしまう事はない。だから、
保存の必要も無い。

レジスタが不足した場合に保存する必要があるのは、必ずレジスタの値。
だから、mov [rsp + disp], reg の形式で十分保存できてしまう。
0099デフォルトの名無しさん
垢版 |
2018/08/18(土) 06:32:40.93ID:v9RxAPQU
>>92
コードセグメントのリテラルならrip相対でエンコードされると思うけど、データセグメントでそれ可能だったっけ?
最近アセンブリ言語いじってないから確認してないけど、それが可能だったら>>85の3はエラーにならないのでは。

>>95
最適化マニュアルのスループットとレイテンシの表見れば書いてあるけど、
push、popはロードユニットやストアユニットだけじゃなくALUも使う。その分無駄。
0100デフォルトの名無しさん
垢版 |
2018/08/18(土) 06:35:45.68ID:v9RxAPQU
push、popはコードサイズに制限のある、プロローグ、エピローグ部分で使うことはあるけど、
あまり必要性はなくなったよ。
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況