X



アセンブラ初心者スレッド 2©2ch.net
レス数が1000を超えています。これ以上書き込みはできません。
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はコードサイズに制限のある、プロローグ、エピローグ部分で使うことはあるけど、
あまり必要性はなくなったよ。
0101デフォルトの名無しさん
垢版 |
2018/08/18(土) 07:05:31.99ID:v9RxAPQU
push、popみたいに複数のμOPになる命令は利用可能なデコーダーも制限されるので
他の命令のデコードも阻害しやすい。
演算命令のメモリオペランドみたいに、フュージョンされて簡単デコーダーで発行できるようになったのもあるけど。
0102デフォルトの名無しさん
垢版 |
2018/08/18(土) 08:53:46.48ID:LWSvYoUk
>>99
>コードセグメントのリテラルならrip相対でエンコードされると思うけど、
>データセグメントでそれ可能だったっけ?

可能。
0103デフォルトの名無しさん
垢版 |
2018/08/18(土) 09:10:13.08ID:LWSvYoUk
>>99
>最近アセンブリ言語いじってないから確認してないけど、それが可能だったら>>85の3はエラーにならないのでは。

エラーメッセージをよく読むと書いてあるけど、linker に、
/LA RGEADDRESSAWARE:NO
というオプションを渡すと、エラーが消える。

これは、[rbp+disp] の disp には、32BIT までしか入れられないので敢えて
エラーを出しているだけなので、本当は特に問題にはならない。
0105デフォルトの名無しさん
垢版 |
2018/08/18(土) 19:54:44.26ID:D84MOd5V
>>103
mov cl, hogehoge
これでアセンブルして、dumpbin /relocations test01.obj
これで見ると
hogehogeがREL32になる(PC相対の32bitオフセット)
ラベルの種類としてRIP相対のREL32はあるけど
通常のレジスタに32bit相対のラベルの種類がないのでは?
だからエラーになると
0106デフォルトの名無しさん
垢版 |
2018/08/18(土) 21:13:26.29ID:D84MOd5V
簡単なWindowsのアプリを作ってWinMainのアドレスを表示すると
0x000000003fdf1770
俺の環境ではこんな値が出た
これってアドレスとしては1GBくらいの位置
下位32bitの絶対アドレスで指定すると符号付と解釈した場合に
残り1GBの範囲しかアクセスできない
だから、64bitのWindowsや/3GBスイッチを指定した32bitWindowsでは
下位32bitの絶対アドレスで指定するなとマイクロソフトは決めたのでは?

RIP相対なら開始アドレスに関係なくRIPの相対値なので
プログラムがロードされた位置に関わらず2GBまでアクセスできる
0107デフォルトの名無しさん
垢版 |
2018/08/18(土) 21:29:59.45ID:D84MOd5V
同じようなプログラムを32bitで作ってコンパイルしたらWinMainの開始アドレスは
0x013215a0
アドレスとしては19MBくらいの位置

64bitアプリは32bitアプリよりもずっと高位のアドレスにロードされるんだろうね
だから64bitアプリでは下位32bitでの絶対アドレス指定は禁止してるのかも
0108デフォルトの名無しさん
垢版 |
2018/08/19(日) 12:41:20.07ID:plhuPGbS
論理的に高位か下位かはどうでもよくね?
0109デフォルトの名無しさん
垢版 |
2018/08/19(日) 16:59:22.46ID:XvleiWNb
>>108
通常のプログラムが扱えるのは論理的なアドレスだからな
関係なくないよ

>>85
    mov   al,my_mojiretu[rbx]    ;3
のような下位32bitの絶対アドレスで指定する場合、扱えるデータの量が減る
上の例では0から2GBの範囲しかアクセスできないのに
論理アドレスで1GB付近からロードされたら扱えるスタティックに割り当てられたデータの量が極端に減ってしまう
0110デフォルトの名無しさん
垢版 |
2018/08/19(日) 17:05:58.03ID:XvleiWNb
だからこそ
>>85
    mov   al,my_mojiretu[rbx]    ;3
のようなコードを書くとリンカがエラーを吐くようになってるんだろうね
下位32bitの絶対アドレスで指定するなと
0111デフォルトの名無しさん
垢版 |
2018/08/19(日) 17:21:35.92ID:XvleiWNb
ほとんどのCPUでは64bitのアドレスを直接指定する方法は限定されてて、実行速度も遅くなる
だからWindowsやLinuxでは64bitでもデフォルトではスタティックに割り当てられたシンボルは
だいたい32bitの値として扱ってる
(Linuxではコンパイラのオプションでメモリモデルを指定できて
スタティックなシンボルを64bitの値として扱うこともできる)

64bit Windowsの場合、かなり高位のアドレスにロードされるようだから
RIP相対の32bitの値として扱ってるのだろう

ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
0112デフォルトの名無しさん
垢版 |
2018/08/19(日) 17:30:58.64ID:XvleiWNb
64bitARMの場合、Linuxではスタティックなシンボル値読み込む場合
adrp x0, :pg_hi21:hogehoge
add x0, x0, :lo12:hogehoge
これで読み込む
これで33bitのページ単位でPC相対のアドレスを読み込める
つまり64bitのARMではスタティックなシンボル値は33bitのPC相対アドレスとして扱ってる
(相対なのはページ単位なので下位12bitは動かせない、下位12bitは絶対アドレス値を足してるので)
0113デフォルトの名無しさん
垢版 |
2018/08/19(日) 17:34:00.29ID:XvleiWNb
64bitのARMのadrp命令と同等の命令はRISC-Vや最近発表されたnanoMIPSなどでも採用されてる
RISC-VやnanoMIPSは33bitではなく32bitだが
0114デフォルトの名無しさん
垢版 |
2018/08/19(日) 17:41:09.62ID:XvleiWNb
スタティックなシンボル値の制約はアセンブラではなくあくまでコンパイラの仕様だが
(コンパイラ側でシンボルを扱う場合にあえて下位32bitしか読み込まない仕様にしてる)
最近のアセンブラプログラミングでは高級言語とリンクすることが多いので必須な知識
0115デフォルトの名無しさん
垢版 |
2018/08/19(日) 19:20:24.59ID:r48xSuow
>>111
> ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
> 64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
> ほとんどのCPUでは64bitのアドレスを直接指定する方法は限定されてて、実行速度も遅くなる

 つまりこういうこと?
・動的に割り当てられたデータは64bitでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitでアクセスするように制限されてるけど実行速度は速い。
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
0116デフォルトの名無しさん
垢版 |
2018/08/19(日) 20:02:42.41ID:XvleiWNb
>>115
>・動的に割り当てられたデータは64bitでアクセスできるけど実行速度が遅くなる

そもそも動的なデータは64bitのポインタで管理されるので最初から全アドレスにアクセスできる

>・静的に割り当てられたデータは32bitでアクセスするように制限されてるけど実行速度は速い。

違う、あくまでシンボルを32bitのアドレスとして読み込んでるだけでデータサイズは関係ない

x86_64でも64bitのアドレスを指定して読み込む命令は限られてるし、
実行速度の面でも効率が悪いのでRIP相対で32bit分だけを使ってる
たとえば、
mov rcx, data01
とした場合、data01の部分はRIP相対の32bitアドレスになる、読み込まれるデータは64bitの値

RISC CPUだとアドレスを読み込んでからデータに読み書きするという2段階になるので
たとえば、64bitのARMだと
adrp x0, :pg_hi21:data01
add x0, x0, :lo12:data01
ldr x0, [x0]
と下位33bitでPC相対アドレスとしてシンボルが読み込まれる

RISC-Vの絶対アドレスだと
lui a0, a0, data01
addi a0, a0, data01
ld a0, (a0)
PC相対だと
1: auipc a0, %pcrel_hi(data01)
addi a0, a0, %pcrel_lo(1b)
ld a0, (a0)
こうなる
(%pcrel_lo()では対応するpcrel_hi()のラベルを指定)
0117デフォルトの名無しさん
垢版 |
2018/08/19(日) 20:06:20.81ID:XvleiWNb
RISC-Vの絶対アドレスのところが間違ってた

不正解
lui a0, a0, data01
addi a0, a0, data01
ld a0, (a0)

正解
lui a0, %hi(data01)
addi a0, a0, %lo(data01)
ld a0, (a0)
0118デフォルトの名無しさん
垢版 |
2018/08/20(月) 06:10:04.15ID:yBkytAxc
>>116
アドレッシングの話をしているだと思ったのではしょったけどこう書けばいいですかね

・動的に割り当てられたデータは64bitアドレッシングでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されてるけど実行速度は速い
・どちらの場合も読み書きできるデータサイズに制限はない
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
0119デフォルトの名無しさん
垢版 |
2018/08/20(月) 07:34:26.88ID:VWtXo5Rn
何で、動的に割り当てられた変数と静的に割り当てられた変数の
アクセス速度を比較するのか意味不明だが
一番アクセスが速いのはローカル変数だと思うぞ

ローカル変数はdisplacement付きのスタックポインタ間接アドレッシングでアクセスできるので
ほとんどのCPUでdisplacementが届く範囲なら1命令でロード、ストアができるからね
0120デフォルトの名無しさん
垢版 |
2018/08/21(火) 13:09:22.87ID:rmPseMne
>>119
今までの話の流れで言うと、速度を比較するのが目的ではなくて、
なぜ静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されているのか?
ですよ。普通に考えたら64bitアドレッシングが制限なくできて当たり前だろ。なんで?ってことです。
0122デフォルトの名無しさん
垢版 |
2018/08/21(火) 16:35:27.52ID:R5Y2p11o
>>120
命令サイズを節約してるだけ
バラバラにコンパイルされた.oに対して後から命令長は変えられないんでデフォでそうなってる
変えたければラージモデルの類のコンパイルオプションがあるはず
0123デフォルトの名無しさん
垢版 |
2018/08/21(火) 19:52:55.59ID:JiPBZbts
>>120
64bitのデータだろうが32bitデータだろうがデータがキャッシュに入ってれば
キャッシュからデータを読み出す速度は変わらないが、
64bitアドレスを即値で指定すると
CISC CPUの場合、64bitアドレスの分、命令のオペランドの長さが長くなるので
今時の複数の命令を同時発行できるCPUだと一度に発行できる命令の数が減るので遅くなる
64bitのアドレスだけで8バイトにもなるからね
RISC CPUの場合は64bitのアドレスを一度に読み込めないので複数の命令に分けて読み込むが
64bitのアドレスを読み込むと命令数が増える

結局、静的データやジャンプ先のラベルはは32bitアドレスに限定したほうが結果的に速くなる
たいていのプログラムで静的データやジャンプ先のラベルで
32bitの範囲を超えるような応用プログラムは極一部の分野だけだしね
その極一部の応用プログラムのために性能を落とす必要はない

スパコンでも使われるLinuxではメモリモデルとして
静的データやジャンプ先のラベルを64bitで扱うようにコンパイルするオプションがある

このページはPGIのコンパイラのページだがわかりやすく説明してある
https://www.softek.co.jp/SPG/Pgi/TIPS/opt_64.htmlはこのページ

ARMやx86_64、POWERのgccでも-mcmodel=largeや-mcmodel=mediumがあったりする
(ARMでは-mcmodel=largeはあるが-mcmodel=mediumはない)
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
https://gcc.gnu.org/onlinedocs/gcc/RS_002f6000-and-PowerPC-Options.html
0124デフォルトの名無しさん
垢版 |
2018/08/22(水) 02:39:05.86ID:J61dDDqI
>>104
確か、そのリンカオプションは、DLL作成時に指定するとエラーになる。

また、アプリの場合だと、relocation 情報が strip されて、EXE ファイルの中にはなくなっているのに対し、DLLだと relocation 情報が最後まで残されたままになっている。

>>105
あなたが使っている用語が x86 や x64 とは合わずめちゃくちゃなので何を聞いているのか分からないが、
hogehoge  db 'xxxx', 0
       mov cl, hogehoe 1
とすると、
        mov cl,[offset hogehode]
と言う意味になり、encode としては、
       mov cl, [RIP + (offset hogehode - offset label1)]
label1:
のように、RIP 相対の disp
       mov cl, [RIP + disp32]
に encode される。この場合の disp32 は、意味としては、rel32 で、
RIP からの32BIT相対アドレス。

一方、似て非なるものとして、
     mov cl, hogehode[rbx]
とすると、
     mov cl, [offset hogehode + rbx]
即ち、
     mov cl, [rbx + disp32]
と翻訳される。この場合の、disp32 は、32BIT絶対アドレス。 同じ、disp32 でも、意味は異なる。しかし、disp は、32BITまでで、 64BIT 値のものは存在していない。一方、64BITアドレスも一応は使えるように、
  mov REG64, ADDR64  ; REG64 は、RAX, RBX, RCX, EDX, RBP, RSI, EDI など。

  mov ACC, [ADDR64]  ; ACC は、al, ax, eax, rax
という命令が、 専用命令として特別扱いとして存在しているが、特殊中の特殊。
0125デフォルトの名無しさん
垢版 |
2018/08/22(水) 02:48:04.81ID:J61dDDqI
>>124
訂正:

hogehoge  db 'xxxx', 0
       mov cl, hogehoge
とすると、
        mov cl,[offset hogehoge]
と言う意味になり、encode としては、
       mov cl, [RIP + (offset hogehoge - offset label1)]
label1:
のように、RIP 相対の disp
       mov cl, [RIP + disp32]
に encode される。この場合の disp32 は、意味としては、rel32 で、
RIP からの32BIT相対アドレス。


ちなみに、masm では、
hoge1   db 'aaa'    ;1

hoge2:  db 'aaa'     ;2
は明確に区別されており、hoge1 は、byte 型の配列変数のような取り扱いになり、
    mov  al, hoge1    ;1
は、masm には通らないが、旧来のアセンブラの感覚で言えば、意味的には、
    mov  al, qword [offset hoge1]   ;3
となり、hoge2 の方は、直後の db 命令とは全く関係の無い単なる near アドレスと解釈され、
    mov  rax, hoge2     ;4
は、意味的には、
    mov  rax, offset hoge2    ;5
となる、ただし、4は、もしかするとそれ自体が文法上、masm の構文に合わないかもしれない。
masm は、「マクロアセンブラ」であって、通常のアセンブラとは結構異なるので。
0126デフォルトの名無しさん
垢版 |
2018/08/22(水) 02:50:10.88ID:J61dDDqI
>>125
誤:    mov  al, qword [offset hoge1]   ;3
正:    mov  al, byte [offset hoge1]   ;3

これも、masm 流には、
    mov  al, byte ptr [offset hoge1]   ;3
nasm 流には、
    mov.b  al, [offset hoge1]   ;3
みたいな感覚。みたいなだけで、実際にはそのまま書くと、エラーになる
かも知れない。
0127デフォルトの名無しさん
垢版 |
2018/08/22(水) 02:55:16.05ID:J61dDDqI
>>124
さらに補足すると、

mov cl, [rbx + disp32]

の disp32 は、rbx の中身によって意味が変わってきて、

1. disp = 32BIT 相対アドレス  (rbx が絶対アドレスの場合)
2. disp = 32BIT 絶対アドレス  (rbx が相対アドレスの場合)

となる。2. の例としては、
  rbx = 配列添え字 * (配列の要素のバイト数)
のような場合。1. の例としては、
  rbx = 構造体の先頭アドレス
のような場合。
0128デフォルトの名無しさん
垢版 |
2018/08/22(水) 04:37:08.89ID:8qwUBnhH
>>127
今やってみたが
64bitアプリを通常にコンパイルした場合のWinMainのアドレス
0x000000013f291770

/largeaddressaware:noを付けてコンパイルした場合のWinMainのアドレス
0x0000000001241770

/largeaddressaware:noを付けるとプログラムがロードされるアドレスが変わる
64bitのアプリを通常にコンパイルするとWinMainのアドレスが0x000000013f291770
およそ先頭から5GBの位置
つまり、32bit絶対アドレスでは届かない位置にプログラムがロードされてる

/largeaddressaware:noをつけると先頭から18MBくらいの位置

エラーが出るのは32bit絶対アドレスでは届かない位置にロードされる可能性があるからだろうな
0129デフォルトの名無しさん
垢版 |
2018/08/22(水) 04:40:24.11ID:8qwUBnhH
補足:
/largeaddressaware:noを付けると64bitアプリでもメモリは2GBまでしか使えなくなる
0130デフォルトの名無しさん
垢版 |
2018/08/22(水) 04:46:45.21ID:8qwUBnhH
つまり、>>128が示してることは

Windowsの64bitアプリでは
mov   al,my_mojiretu[rbx]
のような書き方はしてはいけないということ
0131デフォルトの名無しさん
垢版 |
2018/08/22(水) 08:30:00.67ID:WDZbf6Te
>>124 XvleiWNbとは別人だよね?
/LARGEADDRESSAWARE:NOの辺りからなんか違和感あって、「そうなん?」って感じだったんだけど。
ARMやコンパイラの仕様だとかまで出てきて訳わからなくなるところだったよ。

>一方、似て非なるものとして、
>     mov cl, hogehode[rbx]
>とすると、
>     mov cl, [offset hogehode + rbx]
>即ち、
>     mov cl, [rbx + disp32]
>と翻訳される。この場合の、disp32 は、32BIT絶対アドレス。 同じ、disp32 でも、意味は異なる。

>Windowsの64bitアプリでは
>mov   al,my_mojiretu[rbx]
>のような書き方はしてはいけないということ
今までなんで絶対アドレスが出てくるのか疑問だったけど、コンパイラはこういうコードは吐かない、ってことだよね。
0133デフォルトの名無しさん
垢版 |
2018/08/22(水) 19:39:47.75ID:J61dDDqI
>>130
でも現実は、複雑。

なぜなら、COFFの仕様的には、obj ではない Image(EXEやDLLの事) のためだけに
ある .reloc section には、64BIT 絶対アドレスの再配置も行えるようになっているから。

現状の MS 製の link.exe がどうなっているかはともかく。
0134デフォルトの名無しさん
垢版 |
2018/08/22(水) 19:45:45.82ID:J61dDDqI
>>133
すまん。間違った。
mov   al,my_mojiretu[rbx]
は、意味的には、
mov   al, [rbx + offset my_mojiretu]
となって、最後は、
mov   al, [rbx + disp32]

となるが、disp32 の部分は、disp64 の命令は存在していないので、
.reloc section が 64BIT 絶対アドレスに対応していても、無理だった。

勘違いした。
0135デフォルトの名無しさん
垢版 |
2018/08/22(水) 19:57:50.56ID:J61dDDqI
>>128
一応、論理的には、WinMain は、code (.text) section に置かれる。
my_mojiretu みたいなものは、.data section (など)に置かれる。

my_mojiretu みたいなものは、初期化(初期値)データなので、
2GB も使えれば十分ではあるはず。もし、2GB を超えるのなら、exe ファイルの
サイズも 2GB を超えるはず。

という事で、初期化データのおかれた section のアドレスが、2GB 未満
に置かれるならなんとかなるはず。

というか、通常、exe ファイルは、relocation 情報が strip されているので、
確か、Optional Header の BaseOfCode に配置したいアドレスを入れておける。

だから、その値を小さめにしておけば、初期化データのアドレスを 2GB 未満
の位置に配置する事はそんなに難しくないはず。

確か、32BIT 時代は、0x40000 位の値だった。
0136デフォルトの名無しさん
垢版 |
2018/08/22(水) 20:02:29.70ID:J61dDDqI
>>135
正しくは、BaseOfCode ではなく、ImageBase の方だった。
正しい値は、0x40000 ではなく、1桁大きい、0x400000 だった。
64BIT COFF では、変わってるかもしれない。確か、PREFERED_BASE
などという名前も記憶にある。

ImageBase Preferred address of first byte of image when loaded into memory;
must be a multiple of 64K. The default for DLLs is 0x10000000.
The default for Windows CE EXEs is 0x00010000.
The default for Windows NT, Windows 95, and Windows 98 is 0x00400000.
0137デフォルトの名無しさん
垢版 |
2018/08/22(水) 20:11:19.88ID:J61dDDqI
>>128
自分の勘だと、そのアドレスは、WinMain よりも、DLL の DllMain が置かれるような
値になってるね。

不思議だ。WinMain をそんな大きなアドレスに置く必要性は余り無いハズなので。
初期化データが 2GB 未満に置かれていても、malloc() や、new で確保されるデータは、
64BIT アドレスにできるはずだし。なお、

1_3f29_1770

↑は、32BIT を超えて、33BIT の値だな・・・。なんちゅう大きな値だろう。
0139デフォルトの名無しさん
垢版 |
2018/08/22(水) 21:22:24.95ID:WDZbf6Te
>>134
32bitのフラットメモリモデルだと、静的変数はイメージにはオフセットを入れといて、
実行時にローダで書き換えてたんだと思うんだけど、64bitでは絶対アドレスは制約が大きくなるから変だと思ったんだ。

絶対アドレスはコンパイラでも使えなくはないけど、デバイスドライバでメモリマップトI/O操作するような時しか使わないと思う。
64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
mov   al,my_mojiretu[rbx]
みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?
0140デフォルトの名無しさん
垢版 |
2018/08/22(水) 21:24:18.64ID:WDZbf6Te
例外吐くことで
0141デフォルトの名無しさん
垢版 |
2018/08/23(木) 05:44:12.90ID:sOVf8lyT
>>135
コマンドライン用の簡単なC言語の64bitのプログラムで試したが
main関数のアドレス=0x000000013f7f1000
data sectionで定義した変数data01のアドレス=0x000000013f7fc087
だったぞ
完全に32bit絶対アドレスの範囲を超えてる
0142デフォルトの名無しさん
垢版 |
2018/08/23(木) 07:08:50.83ID:sOVf8lyT
64bitのWindowsアプリを作って.data sectionの変数のアドレスも表示してみた
WinMain address = 0x000000013fd419a0

data sectionの変数のアドレス
data01 address = 0x000000013fd4d000



/largeaddressaware:noを付けた場合
WinMain address = 0x00000000013619a0

data sectionの変数のアドレス
data01 address = 0x000000000136d000
0143デフォルトの名無しさん
垢版 |
2018/08/23(木) 07:09:02.23ID:4LRopBJn
>>139
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
>mov   al,my_mojiretu[rbx]
>みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?

意味不明だ。別に、
mov   al,my_mojiretu[rbx]
というコードが悪いわけではない。

むしろ、最適化のためには使った方が効率が良くなる。
0144デフォルトの名無しさん
垢版 |
2018/08/23(木) 07:22:22.74ID:4LRopBJn
>>141-142
もしそうだとすると、VC++ の吐くコードがx64の命令を上手く使いきれてないという事になる。
本来であれば、アドレスの配置を上手く行うだけで、64BIT モードでも特に問題なく
mov   al,my_mojiretu[rbx]
という命令は使えて、かつ、64BIT アドレスの制限を受けるわけでもないのだから。

ちなみに、アプリの EXE は、リンク後は固定アドレスで、ローダーがアドレスを再配置
する事はない。だから、ImageBase を小さい値になるようにリンクしさえすれば、
問題が生じない。
0145デフォルトの名無しさん
垢版 |
2018/08/23(木) 07:27:31.64ID:4LRopBJn
>>139
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、

通常、コンピュータソフト、特にOSのセキュリティーというのは、そういう人間的なもの
ではなくて、もっと厳密な物だ。

ランダマイズして撹乱して相手の目をくらます、などという方法は通常取られない。

実際、EXE ファイルを解析した経験からしても、ランダマイズなどは全く行われていない。
何回リンクしても、同じアセンブリソースや、同じC++ソースなら、全く同じアドレスになる。
異なるソースであっても、ベースアドレスなどは、ほとんどの場合、固定値。
0146デフォルトの名無しさん
垢版 |
2018/08/23(木) 07:58:52.05ID:4LRopBJn
>>138
実際には問題がある。なぜなら、そんなにアドレスが大きいと、さっきから話題の
mov   al, my_mojiretu[rbx]
という命令が使えなくなるからだ。

これは、グローバルな配列変数を、添え字でアクセスするような場合に良いコードに
なる事がある。僅かではあるが。もし、この命令が使えないとなると、

mov   rdx,offset my_mojiretu
mov   al,[rdx + rbx]

のように、2つの命令を使わなくてはならなくなり、最適化上、不利になる。
0147デフォルトの名無しさん
垢版 |
2018/08/23(木) 08:10:29.27ID:wxGNRrqx
そんな事言い出したら
4GBや64KBに限定した方が小さいコードになるから
compactモデルにしよう
とかいう話にもなる

昔に戻りたい?
何のための64bit?
0148デフォルトの名無しさん
垢版 |
2018/08/23(木) 08:22:23.99ID:4LRopBJn
>>147
だから、そういうことじゃなく、EXEファイルの中に、2GBを越える初期化データを
誰が入れたいかって話なんだ。

別に、ImageBase を小さい値にしていても、malloc() や、new するデータは、
6GBでも理論上は確保できるわけで、制限されるのは、EXEファイルの中の
初期化データのサイズが2GBまで、ってだけなんだ。

それで、使えるマシン語の間接オペランドの種類が1つ増やせる。
mov 命令だけでなく、add, sub, mul, div, idiv, lea, addps, addss などにも
全て影響する貴重な間接オペランド。
0149デフォルトの名無しさん
垢版 |
2018/08/23(木) 08:46:40.08ID:4LRopBJn
>>147
8086時代の 64KB では制限が大きすぎて、ほとんどのプログラムで、制限が足かせ
になっていたので、32BIT になって、アドレスが 4GB に拡張されて非常に便利になった。

ところが、64BIT 時代になっても、そのときのようなメリットが無いと思うんだ。
AMD vs Intel の競争の結果出てきた産物かも知れない。そういうの、時々ある。
0150デフォルトの名無しさん
垢版 |
2018/08/23(木) 08:56:25.66ID:K9a3gVgQ
>>145
WindowsではASLRでランダム化普通にやってるらしいですよ

http://07c00.hatenablog.com/entry/2013/08/07/033443
OSがプロセスをロードするときに、ランダムな場所にモジュールを配置するセキュリティ機能です。
実際はモジュールだけじゃなく、スタックやヒープなどもランダマイズされたりします。
0151デフォルトの名無しさん
垢版 |
2018/08/23(木) 09:03:22.89ID:4LRopBJn
>>150
少なくとも、EXE の .text, .data セクションは再配置される事は無いはず。
なぜなら、.reloc section が存在せず、再配置する事が原理的に出来なくなっているから。

DLL は、.reloc section が残されているので再配置できる。ただし、再配置しなくても、
全てのシステムのDLLは、最初からアドレスが重ならないような ImageBase になっている
ので、再配置されずにそのままおかれるのが、昔は基本であった。
0152デフォルトの名無しさん
垢版 |
2018/08/23(木) 10:25:25.69ID:3bgfj1QZ
>>148
64bitコードで絶対番地に依存したコードとか
考え方が古いねえ

ていうか、
イヤなら2GB限定のコードにすればいい
コードもデータも2GBの範囲に割り当てられるから
0153デフォルトの名無しさん
垢版 |
2018/08/23(木) 11:01:43.32ID:4LRopBJn
>>152
じゃあなんで、MS純正VSは、いまだに 32BIT コードで動いてるのさ。

x64 は、レジスタが増えた事と、memmove() などが多分、倍の速度で動く事が
最大のメリットじゃないの?

アドレス幅が64BITになって現実的なメリットはどこにあるのかな?
0154デフォルトの名無しさん
垢版 |
2018/08/23(木) 11:36:32.13ID:3bgfj1QZ
なにが「じゃあ」だか

メリットが無いと思うなら2GB限定のアプリにすれば良い
って書いたのが見えなかった?
0155デフォルトの名無しさん
垢版 |
2018/08/23(木) 12:51:14.26ID:4LRopBJn
>>154
だから、メリットはあるよ。
レジスタが増えること、AVX, AVX2, AVX512 で、YMM, ZMM レジスタでベクトル
の次元が大きくなったSIMD 命令が使えること、3オペランドの以上のSIMD命令が使える
事、メモリ転送の速度が倍近くになること。malloc(), new が、2GB を超えて行える事。

初期化サイズが2GBを越えるメリットは余り無いと思ってるけど。
0156 ◆QZaw55cn4c
垢版 |
2018/08/23(木) 17:09:15.42ID:NMfUyUL+
>>149
アドレス空間は広いほうがいいに決まっている
ユーザーアドレス空間の断片化は基本防止できない、だったら入れものが広いほういい
0159デフォルトの名無しさん
垢版 |
2018/08/23(木) 19:03:15.16ID:sOVf8lyT
>>148
結局、
mov   al,my_mojiretu[rbx]
こんなコードを書くと64bitではLINKする時にエラーが出る
/largeaddressaware:noを指定するとLINKでエラーは出なくなるが、
/largeaddressaware:noを指定すると動的メモリも含め2GB以下のメモリしか扱えなくなる
0163デフォルトの名無しさん
垢版 |
2018/08/23(木) 19:52:19.27ID:sOVf8lyT
バーチャルYoutuberなんかでも使われるソフト(エロゲ)だが
64bit Windowsのみ対応
動画配信などで結構使われてる

CUSTOM ORDER MAID 3D2
http://com3d2.jp/main.html
OS Windows® 7/8.1/10 全て64bitのみ対応 ※6
※6:32bitOSには対応しておりません。
0165デフォルトの名無しさん
垢版 |
2018/08/23(木) 20:05:15.44ID:sOVf8lyT
>>153
10年位前に出来たオンラインゲームでも、今はもう2GBのメモリだともう足りなくて
32bitのゲームでも/LARGEADDRESSAWAREのフラグ立てて延命してるのもあるよ
64bit WindowsならLAAフラグを立てると32bitアプリでも4GBまで使えるようになる
LAAで延命してるゲームで32bit Windowsで遊ぶとメモリ不足で高確率で落ちるゲームとか既にある
0168デフォルトの名無しさん
垢版 |
2018/08/23(木) 20:16:43.95ID:sOVf8lyT
ちなみにこのブログ書いてるところはWindows用ソフトもいくつか出してるところだよ
0169デフォルトの名無しさん
垢版 |
2018/08/23(木) 20:18:49.99ID:sOVf8lyT
>>167

>>165のこと?

一応、32bitWindowsもサポートしてるがメモリが足りなくなってよく落ちるので
実際は64bit Windowsでしかまともに遊べないってこと
そういうゲームが既にある
0171デフォルトの名無しさん
垢版 |
2018/08/23(木) 20:34:21.09ID:sOVf8lyT
>>146
実際にどの程度、速度が変わるのか試してみて欲しいもんだな
ただの机上の空論じゃないのか?

大体、配列で何回もデータにアクセスするなら
32bitのDISPを毎回指定するオーバヘッドだってあるんだが
0173デフォルトの名無しさん
垢版 |
2018/08/23(木) 21:13:40.67ID:sOVf8lyT
mov rcx, offset HOGEHOGE01
mov rax, qword ptr [rcx + rbx]
mov rax, qword ptr [rcx + rbx]
mov rax, qword ptr [rcx + rbx]
mov rax, qword ptr [rcx + rbx]
これと
mov rax, HOGEHOGE01[rbx]
mov rax, HOGEHOGE01[rbx]
mov rax, HOGEHOGE01[rbx]
mov rax, HOGEHOGE01[rbx]
これを250個並べて1000万回ループさせてみたが、1%くらいしか差はないよ
0175デフォルトの名無しさん
垢版 |
2018/08/24(金) 00:12:57.34ID:568m+iHd
なんで訳分からなくなりそうになったのか理解できたw
4LRopBJnが変なんだな。

Microsoftが64bitでは絶対アドレスのインデックスは使わないって決めたんだから、その流儀に従うのが高級言語とリンクだよ。
0176デフォルトの名無しさん
垢版 |
2018/08/24(金) 00:23:58.73ID:568m+iHd
>>167
メモリが厳しいなら、ヒープが断片化すればメモリ確保できなくなっても不思議じゃないよ。
それなら確率的に落ちると思う。
0178デフォルトの名無しさん
垢版 |
2018/08/24(金) 01:50:43.81ID:PMMpdZPT
>>159
いや、それはあなたの勘違い。

そのオプションを指定しても、EXEの中に入っている「初期化データ」のアドレス
が2GB以下に限定されるだけで、動的メモリは、理論上は、100GB でも一気に
確保できる。それは、再三言ってる。あなたは理解出来てないと思う。
0179デフォルトの名無しさん
垢版 |
2018/08/24(金) 01:54:49.18ID:PMMpdZPT
>>164
再三言ってるけど、あの/LARGEADDRESSAWARE:NO オプションを
付けても、「初期化データ」のアドレスが2GBに制限されるだけで、
new や malloc() などの、ヒープから確保される動的メモリは、64GBの
アドレス空間どこにあっても問題ないんだよ。
0180デフォルトの名無しさん
垢版 |
2018/08/24(金) 02:00:34.30ID:PMMpdZPT
>>173
そりゃ分かってるよ。

でも逆に、EXEファイルの中に最初から入っている「初期化データ」
の2GB制限とどっちが良いかの話になるんだよ。もちろん、動的メモリ
は何の制限も受けず、64GBアドレスが好きなように使える。

初期化データというのは、何かの埋め込みテーブルのための配列
だとか、文字列データとか、そういうものだよ。

巨大な3Dモデルデータ、テクスチャ、マップデータなどは、外部ファイル
にでも置いておけば、2GBの制限は受けず、仮想アドレスとしては
64BITまるまる使えるから。

実際、EXEの中にある初期化データが2GBを越えるという事は、
EXEファイルが2GBを越えるという事だから、そのアプリの起動
時には、有無を言わさず HDDなどから、2GBの読み込みが
始まってしまうことになる。
0181デフォルトの名無しさん
垢版 |
2018/08/24(金) 02:02:34.25ID:PMMpdZPT
>>179 >>180
【誤字訂正】
誤:64GBアドレス
正:64BITアドレス

言葉は間違っているが、中身は間違ってない。数学は100点、国語は赤点
の学生時代だったし。
0182デフォルトの名無しさん
垢版 |
2018/08/24(金) 02:18:09.88ID:PMMpdZPT
>>173
それでもやはり、1%の速度低下にはなったんだよね。

「初期化データの2GB制限」は、現実的には何の制限にもなってない
事は理解出来てる???? 動的メモリは、64BIT 自由に使える
んだよ。
0183デフォルトの名無しさん
垢版 |
2018/08/24(金) 04:19:33.40ID:CXKCSzYg
>>178、179
実際にやってみれば?
C言語でmallocでもvirtualallocでも
/largeaddressaware:noを付けると動的メモリも2GB以下しか確保できなくなるから
0184デフォルトの名無しさん
垢版 |
2018/08/24(金) 04:38:15.52ID:CXKCSzYg
>>182
実際に試したことないのが丸わかり
/largeaddressaware:noをつけると本当に試してみるといいよ、
動的メモリも2GB以下しか確保できなくなるから

このページの
https://www.webtech.co.jp/blog/optpix_labs/programing/6387/
この図に載ってるプログラムでも試せるよ
https://www.webtech.co.jp/blog/wp-content/uploads/2013/11/laa_test_prg_thumb.png
0185デフォルトの名無しさん
垢版 |
2018/08/24(金) 04:39:04.29ID:CXKCSzYg
上のプログラムだと/largeaddressaware:noを付けない時に
無限に確保するので4500MBで終わるように少し改変してみた
これで試してみな

#include <windows.h>
int PASCAL WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmd, int n)
{
int step = 10; //10MB
int count = 0;
char temp[20];
for (;;)
{
void *p = GlobalAlloc(GPTR, step * 1024 * 1024);
if (p == NULL)
{
break;
}
count++;
if(count > 400 + 50) {
break;
}
}
wsprintf(temp, "Total %d MB\n", count * step);
MessageBox(NULL, temp, "alloc test", MB_OK);
}
0187デフォルトの名無しさん
垢版 |
2018/08/24(金) 05:30:48.46ID:CXKCSzYg
そもそもWindowsは/largeaddressaware:noを付けなくても静的データは2GBまでしか使えない
動的データだけがOSが対応してるメモリ分だけ制限なく使える
WindowsにはLinuxのgccのような-mcmodel=largeや-mcmodel=mediumのようなオプションは存在しない

/largeaddressaware:noを付けると64bitアプリでも動的メモリも含めてすべてのメモリで2GB以下までしか使えなくなる

PGIのコンパイラのページでわかりやすく解説してあるよ
https://www.softek.co.jp/SPG/Pgi/TIPS/opt_64.html
0189デフォルトの名無しさん
垢版 |
2018/08/24(金) 07:30:57.16ID:ZkSPfVdV
>>182
そこだけ抜き出して、
しかも最適化してないコードで1%
こんなコードは全体の中では非常にわずかだろうし
タイムクリティカル部分であれば最適化される

実質差が無いメリットの為に絶対アドレスに依存したコードにする
時代に逆行だ

それでも逆行したければ
0〜2Gのアドレスしか割り当てられない2G限定アプリにしろ
0192デフォルトの名無しさん
垢版 |
2018/08/24(金) 07:53:32.13ID:CXKCSzYg
>>191
25個並べることにしてループ回数を一桁増やしたが早くならないぞ
そういうのを机上の空論というんだ
0193デフォルトの名無しさん
垢版 |
2018/08/24(金) 07:59:52.52ID:568m+iHd
なんか初心者スレの趣旨とずれまくりなんだけど。
コンパイラのABIが「変わった」のなら、それに合わせたのを紹介しないと。

Visual Cは64bitではインラインアセンブラも使えなくなったし、AVXやSSEは組み込み関数で大概は満足できるはずって判断されたのだろう。
今のご時世わざわざアセンブリ言語でプログラミングしたいって用途は動画のコーデックやフィルタプラグインDLL、将棋とかの思考ルーチンとかでしょ。
こういうのは2GB制限下でしか使えないコードでは困るはず。
0194デフォルトの名無しさん
垢版 |
2018/08/24(金) 08:09:12.98ID:568m+iHd
>>189
静的配列だとサイズが決まってるから、恐らく最適化されてポインタとオフセット(ディスプレースメント)に変換されるよね。
>実質差が無いメリットの為に絶対アドレスに依存したコードにする
>時代に逆行だ
これに同意。
0196デフォルトの名無しさん
垢版 |
2018/08/24(金) 14:52:13.41ID:PMMpdZPT
>>185
自分は 64BIT 用C/C++コンパイラをインストールして無いので、試せません。

link.exe に、 /largeaddressaware:no を渡した場合にのみ、
GlobalAlloc() が失敗する理由は何ですか?

ポインタが32BITになる? それとも、GlobalAlloc の関数が別のものに
入れ替わってしまう?

そのどちらでもないとしたら何が原因ですか?
0197デフォルトの名無しさん
垢版 |
2018/08/24(金) 14:54:32.88ID:PMMpdZPT
>>187
>/largeaddressaware:noを付けると64bitアプリでも動的メモリも含めてすべてのメモリで2GB以下までしか使えなくなる
>PGIのコンパイラのページでわかりやすく解説してあるよ
>https://www.softek.co.jp/SPG/Pgi/TIPS/opt_64.html

リンク先のページを見たのですが、自分には、
 「動的メモリの場合にも2GB以下しか使えなくなる」
という文書が見つかりませんでした。

どこに書かれているか、ご指摘いただければ幸いです。
0198デフォルトの名無しさん
垢版 |
2018/08/24(金) 16:51:48.72ID:VlbdtNmU
実験したけど2GBまでだったよ
malloc

アドレスは32bitで保持出来る
32bitアプリからの移植用だろうね
0199デフォルトの名無しさん
垢版 |
2018/08/24(金) 16:55:58.09ID:VlbdtNmU
>>196
メモリはOS側の管理でしょ?
OSがアプリ種別を判別してアドレスを割り当てる

31bit
32bit
64bit

の3種類かな?
0200デフォルトの名無しさん
垢版 |
2018/08/24(金) 17:07:40.76ID:PMMpdZPT
>>199
リンカオプションによって、API の挙動まで変わってしまうんでしょうか。

そして、Win64 API の GlobalAlloc() などが返す値が 31 BIT までに
なるので、malloc() もそれにつられて、勝手に 31BIT までになると?

64BIT COFF だと、COFF Image に、/largeaddressaware:no かどうか
を示す BIT か何かが追加された???
0201デフォルトの名無しさん
垢版 |
2018/08/24(金) 19:11:45.47ID:5OB8VNk6
>>196
無料のVisual Studio Expressでも2013以降は64bitのビルドにも対応してるよ
64bitのWindowsプログラミングに興味があるなら入れてみれば?

プログラムのコードを見ればわかるように
10MBずつメモリを確保していき
メモリが確保できなくてGlobalAllocの戻り値にNULLが返るか
確保したメモリが4500MBを越えたらbreakでループを抜けて
確保したメモリ容量を表示して終了するようになってる

で、/largeaddressaware:noを指定すると
俺の環境では1970MB確保したところでループを抜けて終了してる
つまり、1970MB確保したところで、
次にGlobalAllocを実行するとメモリが確保できなくてNULLが返る
これは、動的メモリも2GB以下しか確保できないということを示してる

/largeaddressaware:noを指定せずにコンパイルすると
4510MBまで確保して終了する
0202デフォルトの名無しさん
垢版 |
2018/08/24(金) 19:16:32.91ID:5OB8VNk6
>>200
Visual Studioに入ってるdumpbin.exeでコマンドプロンプトで
dumpbin /headers hogehoge.exe
とやると/largeaddressawareを指定した状態(/largeaddressaware:noを指定しない状態)だと
FILE HEADER VALUESの項目とのところに

Application can handle large (>2GB) addresses

これが表示される
なので詳しくは知らないが実行ファイルの中に/lageaddressawareの指定をする部分があるはず


これまたVisual Studioに入ってるeditbin.exeを使うと
実行ファイルそのものに/largeaddressawareや/lageaddressaware:noの指定ができる

LAAを有効にするには
editbin /lageaddressaware hogehoge.exe

LAAを無効にするには
editbin /lageaddressaware:no hogehoge.exe
0203デフォルトの名無しさん
垢版 |
2018/08/24(金) 19:47:12.65ID:568m+iHd
VCで64bitの静的配列にアクセスするコードを調べてみた。
#include <math.h>

volatile char str[1024];
volatile char c;

main(int argc, char *argv[])
{
int idx;

idx = (int)(rand() * 1024);
c = str[idx];
}

これの配列アクセス部分が
; 11 : c = str[idx];

0001c 48 63 44 24 20 movsxd rax, DWORD PTR idx$[rsp]
00021 48 8d 0d 00 00
00 00 lea rcx, OFFSET FLAT:str
00028 0f b6 04 01 movzx eax, BYTE PTR [rcx+rax]
0002c 88 05 00 00 00
00 mov BYTE PTR c, al

00028は[rcx+rax]で配列アクセスしてる
そして、00021と0002cはrip相対アドレッシングだよね?(エンコードは自信ないので)
0204デフォルトの名無しさん
垢版 |
2018/08/24(金) 19:58:50.48ID:568m+iHd
>>198
時々ポインタをDWORDに変換して構造体に突っ込んでたりすることがあるからね。
argeaddressawareは、こういうコードが含まれたアプリをどうしても64bitで動かさなきゃいけなくなった時とかに仕方なく使うオプションでしょう。
でないと、GlobalAlloc()が大きなアドレス返したら動かなくなるし。
0205デフォルトの名無しさん
垢版 |
2018/08/24(金) 20:08:42.11ID:568m+iHd
>>200
プロセスを起動する時にexeのLAAフラグを見てメモリとかハンドルを返すAPIが32bitに収まる値を返すように設定されるんだと思う。
こういうのはプロセスごとに32bitとかにも切り替えられる(この場合はシステムDLLは64bitとは別だけど)ので、
互換性を確保する仕組みが裏で動いてるはずだよ。
0206デフォルトの名無しさん
垢版 |
2018/08/24(金) 20:18:03.36ID:568m+iHd
>>203のコードバイトの折り返し部分のタブが詰められて見にくいので

0001c 48 63 44 24 20 movsxd rax, DWORD PTR idx$[rsp]
00021 48 8d 0d 00 00 00 00 lea rcx, OFFSET FLAT:str
00028 0f b6 04 01 movzx eax, BYTE PTR [rcx+rax]
0002c 88 05 00 00 00 00 mov BYTE PTR c, al
0207デフォルトの名無しさん
垢版 |
2018/08/24(金) 21:46:35.00ID:5OB8VNk6
>>203
VC++だと/FAオプションを指定するとアセンブラ出力もされるよ
ただ、64bitのVC++コンパイラが吐き出すアセンブラコードは
そのままではml64.exeでアセンブルできないけど
ml64.exeでアセンブルできるように修正できたらml64.exeでアセンブルする時に
/Flオプションを指定するとリスティングファイルを出力してくれる
0208デフォルトの名無しさん
垢版 |
2018/08/24(金) 22:08:39.28ID:568m+iHd
>>207
>>203は/FAscで出力された.codから抜粋したもので、リンク前だから変数のアドレスが変な値になってる。
最適化オプションつけ忘れてるのでimul使ってるけど、/O2でも配列へのアクセスはインデックスレジスタ付きなのは変わらなかった。

このサンプルでは配列の添え字がコンパイル時に推定できないようにしたのでインデックスレジスタ付きになってるけど、
普通のループでは、この部分は最適化されてポインタに変更されて、レジスタ間接とポインタ操作するコードになるはず。
0209デフォルトの名無しさん
垢版 |
2018/08/25(土) 04:35:15.70ID:gxBSyOuw
プロセスのアドレス空間が、4GB までだから

その内、Linux では1GB、Windows では2GB を、カーネル空間に割り当てているから、
残りのユーザー空間は、3GB, 2GB になる

カーネル空間は、全プロセス共通の空間だから、各プロセスで使えないアドレス
0210デフォルトの名無しさん
垢版 |
2018/08/25(土) 05:52:55.11ID:5KTEEpUR
64bit Windowsでの2GB制限ってのは、単にメモリ確保時のアドレスの割り当て方やハンドルの値が変わるだけで、
アクセスできない場所では普通に例外が発生するだけのこと。
/largeaddressaware:yesの状態では、32bitの範囲のアドレスがが割り当てられてないから
rip相対を使って静的変数のあるアドレスを取得するってことね。
0211デフォルトの名無しさん
垢版 |
2018/08/25(土) 05:57:44.86ID:5KTEEpUR
割り当てられてないってのは変だったね。
アクセス権限が与えられてないからってこと。
0212デフォルトの名無しさん
垢版 |
2018/08/25(土) 11:07:20.24ID:auNeFg4G
偉そうなもんだな。
もうちょっと、言い方ってもんを学んだ方がいい。
人間性に問題あるかも。
0213デフォルトの名無しさん
垢版 |
2018/09/03(月) 04:21:34.86ID:A+X9ST7o
アセンブラの命令を覚えたいのと
デバッガーを使いこなしたいんですが
何かお勧めの勉強方法はありますか?
C入門程度だけの知識だけでアセンブラは全く知りません

よろしくお願い致します
0214デフォルトの名無しさん
垢版 |
2018/09/03(月) 11:24:23.57ID:dhYkuZhG
CPUは何?
0215デフォルトの名無しさん
垢版 |
2018/09/03(月) 12:38:16.62ID:f+M/nyW5
書いてないってことは決まって無いんだろう

Visual Studio Community 2017
x86 64bit
ml64.exe

が環境としては一番簡単かな
何もしない関数をアセンブラで作って
Cからその関数を呼ぶところから始めよう
0216デフォルトの名無しさん
垢版 |
2018/09/03(月) 20:27:11.25ID:A+X9ST7o
os10 64bitです
C++でアセンブラ使えるんですね
知りませんでした。そこら辺も調べてみます
デバッガーでコードを読んで書き換えられるようになりたいです
0218デフォルトの名無しさん
垢版 |
2018/09/04(火) 16:50:20.52ID:ErgP6cOz
横からだけど、
それに必要なのはバイナリからアセンブラコードを出力する逆アセンブラじゃないの?

それとも基礎知識として習得したいってことなのか
0220デフォルトの名無しさん
垢版 |
2018/09/04(火) 22:32:50.81ID:snmgssEj
>>218
これから勉強するって段階で逆アセはまだ早い。まずCで簡単なコード書いてアセンブラソース出力
それを見て少しずつ変更して動作を勉強。どきどき暴走させて遊ぶのがいい。
Cやアセンブラのソースがないバイナリを逆アセしても、逆アセはコードとデータの区別なしにコード化するから混乱する。
0221デフォルトの名無しさん
垢版 |
2018/09/04(火) 22:50:42.54ID:bj+tb6HS
回答ありがとうございます;
アセンブラの実行環境整える(実機だのエミュだの)用意するのが物凄い敷居高そうに感じるので
チートエンジンやollydbg?ってやつでオフライン用のゲームでも解析しながら
アセンブラ命令群を覚えようと思ってます。
アセンブラの命令を覚えるのだけなら後者でも力つきますかね?目標はウイルスのデバッグとか出来るようになりたいです
0222デフォルトの名無しさん
垢版 |
2018/09/05(水) 01:22:32.69ID:vQx16S6k
>>221
>目標はウイルスのデバッグとか出来るようになりたいです
どうしてそう反社会的な方ばっかり目がいくんだい。

これだから、ハッカー=クラッカー、悪者、のイメージが付く。
昔は、アセンブラといえば、速さのために学んだものなのに。

君みたいなのにはプログラムになんか興味を持たないで欲しい。
0223デフォルトの名無しさん
垢版 |
2018/09/05(水) 02:37:54.86ID:wyXCwUhn
>>どうしてそう反社会的な方ばっかり目がいくんだい。

そう…ではなくてですね
将来ウイルスとかランサムウェアの対策ツールとか作ってみたいから
デバッグスキル付けたいと思って、覚えたいと思いました。
http://www5c.biglobe.ne.jp/~ecb/assembler/assembler00.html 見て実行環境頑張って作って覚えようと思ったんですけど
とっつきづらすぎると思って;
てかVisualStudioって自分のコードアセンブラで出力したり出来るんですね
全然知りませんでした。ありがとうございます
0224デフォルトの名無しさん
垢版 |
2018/09/05(水) 03:52:48.57ID:EatH13os
ウィルスってね、勉強のつもりで作っても、いざ出来上がると使ってみたくなるもんなんだよね。
そういう誘惑に勝てるかどうか
0225デフォルトの名無しさん
垢版 |
2018/09/05(水) 06:27:13.70ID:wyXCwUhn
>>224
そういう方もいらっしゃるんですね。
プログラミング歴はもといパソコンも初心者レベルにしかない自分には縁のない響きですね・・

ところでC++のコードをvisualstudioでアセンブラ出力とはどうやるんでしょうか?
気になって調べてみたんですが デバック(D)→ウィンドウ→アセンブラ っと進むと出てくると書いてあるんですが
そんな項目ありません;
0226デフォルトの名無しさん
垢版 |
2018/09/05(水) 11:13:33.31ID:/V9AsOwQ
debug.exe
debug64.exe
0227デフォルトの名無しさん
垢版 |
2018/09/05(水) 11:34:16.13ID:TWmx8fnR
OllyDbg とか、

うさぴょんの「うさみみハリケーン・スペシャルねこまんま」とか、
将棋AI「やねうら王」の作者、やねうらおの本「解析魔法少女 美咲ちゃん」とか

デバッガによるx86プログラム解析入門 【x64対応版】、うさぴょん、2014
0228デフォルトの名無しさん
垢版 |
2018/09/05(水) 11:55:15.09ID:gDSR0MtA
>>225
ソリューションエクスプローラーでソリューションの下にあるプロジェクトを選択してプロパティ
構成プロパティ→C/C++→出力ファイル→アセンブリの出力
0230デフォルトの名無しさん
垢版 |
2018/09/06(木) 01:20:57.16ID:UZSBUUik
VSでC/C++のデバッギングに入ってステップインしてたらアセンブラのコードが出てこないか?
0232デフォルトの名無しさん
垢版 |
2018/09/06(木) 05:22:06.40ID:psScFFtw
Cならインラインアセンブラ使えば良いんでない?
0234デフォルトの名無しさん
垢版 |
2018/09/24(月) 01:13:48.37ID:rSek34EX
取り敢えずアセンブラ上の数字2進数(或いは16進数)を桁ごとに分けて十進数にして、+30して(文字コードに変換)する事には成功した。

何進数か関係無く、10の位なら10ずつ、100の位なら100ずつ引いて実現。

筆算のアルゴリズムだともっと速いらしいので、時間があれば挑戦したい。
時間があれば。。。
0235デフォルトの名無しさん
垢版 |
2018/09/24(月) 01:17:43.11ID:rSek34EX
x 何進数か関係無く、10の位なら10ずつ、100の位なら100ずつ引いて

o 何進数か関係無く、(何進数の10でも10進数の10だと言うことは変わらないので)10の位なら10(16進数だとA)ずつ、100の位なら100ずつ引いて
0236デフォルトの名無しさん
垢版 |
2018/09/25(火) 01:58:20.74ID:4rHiZGxF
8bitISAの経験はあるんだがIA32やAMD64のプログラミングマニュアルを見ると命令の多さにめまいがする
しかもググってみるとメモリアドレッシングもなにやら作法があるようでよくわからん・・・
な状態なのだがIA32/AMD64のアセンブラを勉強するのにおすすめの資料とかあるかな
今のところ自力で書いたことのあるISAは78K0S、8051、AVR。基本的な概念はわかっているつもり
リンカ周りは不安あり。プラットフォームはWindowsかLinuxかFreeBSDを検討中
0238デフォルトの名無しさん
垢版 |
2018/09/25(火) 09:25:52.53ID:oRUMH9qn
ISA=instruction set architecture=命令セットアーキテクチャ
や、
ISA=PC/ATの拡張スロットのバス仕様

??
0242デフォルトの名無しさん
垢版 |
2018/09/27(木) 10:28:07.85ID:+X2PETpr
>>240
アスペじゃなければこの文脈でそれはない
0244デフォルトの名無しさん
垢版 |
2018/09/27(木) 10:58:42.91ID:JRG0evD8
かなりアセンブラ経験あるけど、8bit ISAと聞いても意味が分からなかった。
多分、8bit CPUとか、8bit マイコンのことが言いたかったのではないかとは
思ったけど、意味がはっきりしなかったので念のため聞いてみた。

個人的には、Instrucstion Set Architectureの意味での「ISA」という
言い方は、Intelのマニュアルなどで最近目にするようになった印象が
ある言い方。

修正に告ぐ修正を重ねてが複雑化したx86系CPUのあの複雑さのニュアンス
を出すためにIntelが使い始めた言葉かもしれない。

昔、Z80が流行っていたころは、日本の雑誌などでは、8bit CPUと言われて
いたし、炊飯器や冷蔵庫では、今でもCPUよりもどちらかというと
I/OポートやA/Dコンバーターを内蔵しているみたいななニュアンスを
含めて「マイコン」と言われていると思う。

ISAという言葉は、Intelマニュアル以外ではあまり見たことない。
0245デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:23:55.29ID:tmnyfQyv
ARM でも MIPS でも普通に ISA 使うけど。
8bit の頃は、セカンドソースはあっても、ISA レベルでのライセンシングが無いか稀だったんじゃないかなあ。

どっちにしろ、16bit バスの ISA を思いつくのはちょっと理解できない。
0246デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:29:57.13ID:JRG0evD8
>>245
文化が違うと用語も違う。Z80 ISAなんて言葉は一度も聞いたことがない。
8BIT ISAも初耳だった。

8BIT時代、ARMやMIPSも日本では聞かなかったし。
0247デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:40:30.81ID:JRG0evD8
>>245
「8-bit ISA card」
で検索すると、色々出てくる。

当時、愛器はNEC製だったのでPC/ATのバス規格であったところのISA
については知らなかったけど。

コンピュータは用語が多様なので、省略形は注意が必要だと思う。
ガングロ女子高生が省略後で通じ合えるのは、多分、興味の対象が
狭いか、語彙が少ないからこそかもしれないと思ってる。
語彙が豊富な人ほど、略さずそのまま言う傾向があると思うし。
0248デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:40:33.72ID:tmnyfQyv
>>246
うん、だから ISA レベルでのビジネスがない頃はそこにタームが存在してなかっただけで、今の時代であれば、8bitISA と言われれば、いろんな8bitマイコンの事だと判るでしょ。
おまけに、その下に
自力で書いたことのあるISAは78K0S、8051、AVR
って書いてあるんだから。

>>236
FreeBSDかNetBSDの mm とか syscall とか libc 周り読むのがいいと思う。
本なら、はじめて読む486 は良かった記憶があるけど相当昔の話だし x64 はないからおすすめ度は低い。
Kindle あるみたいだから、気が向いたらレベルでおすすめ。
0249デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:49:44.12ID:JRG0evD8
>>248
あまりなじみの無いCPU名が列挙されていたので、8bit ISA BUSで、組み込み系
をやっていた人かと思ったんだよ。

ネットでは、質問者の年齢も分からないし、何にも推測できないから。
0250デフォルトの名無しさん
垢版 |
2018/09/27(木) 11:55:04.47ID:JRG0evD8
アセンブラの基礎が分かっている人なら、Intelの3 Volumeがセットになった
英文マニュアルがお勧め(なお、英語が分かる人は、日本語版は読まない
方がいいと思う。混乱の元になるから。英語が分からない人は、多分、
混乱しながら時間をかけて前後関係から推定して理解することになる。)

ModRMについても書いてある。ただし、32BITのものが詳しく書かれていて、
64BITのものについては、補足のように後から書かれている。
REX prefixとかと関連して。

非常に壮大なマニュアルで、忘れたけど、総ページ数は5,000ページくらい
あったかもしれないけど、必要なところをかいつまんで読めばいい。

アセンブラ経験がある人なら読めるはず。
0251デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:02:53.61ID:yf1/OigC
みんなここを読んでいるのが自分と同じ業界の専門家だと思っているのかな?
初心者スレなんだから上級者は来るなよ
0252デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:09:02.87ID:JRG0evD8
>>250
PDFファイルは、Adobe純正のものではなく、SumatraPDFがお勧め。
場合によっては、それと、PDF-XChange Viewerとの両使いも便利。

2つのビューアーがあると、同じファイルの異なるページを同時に
見ることが出来る。

特に、SumatraPDFは、ネットブラウザやWindows用の
テキスト・エディタなどとよく似た使い勝手で便利。
0253デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:29:35.23ID:nUEopGTJ
>>245
ISAってISAバスしか思い浮かばないんだがw
アセンブラやるなら、ASMソースとかニーモニックコードとかのほうが一般的だろうね
0254デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:30:49.36ID:lrUHFZkm
自分の知識不足を棚に上げて絡む馬鹿アスペ
0255デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:34:10.71ID:JRG0evD8
お互いに知識に偏りがあるからしょうがないんだよ。

だから、分からない言葉があれば言葉の確認が必要となると思う。

名プログラマやIQ170の人でも、知らない分野では知識不足はあるよ。
0257デフォルトの名無しさん
垢版 |
2018/09/27(木) 12:59:24.22ID:JRG0evD8
>>256
78K0Sが、NEC製のマイコンだということだけは、昔知ったことがある。
でも、昔といってもとても最近。

8051は、PC-8801のシリアルコントローラに、似たような型番のものがあったような
気がしたが、たぶん関係ないけど、正確な型番は思い出せない。
0258デフォルトの名無しさん
垢版 |
2018/09/27(木) 13:05:15.67ID:JRG0evD8
>>256
8251が、Serial Controller、8255 がParallel Controller、
8085、8086がCPUだった。

8051というのは、知らないかも。
0259デフォルトの名無しさん
垢版 |
2018/09/27(木) 16:23:11.07ID:JRG0evD8
>>236
命令が多いのは、基本的には、MMX, SSE〜SSE4, AVX, AVX2, AVX512 が
追加されたことが大きい。その辺の命令はまずは、無視。
整数命令(汎用命令)から見るといい。
なおその前に、どんなレジスタがあるかについて勉強する。
「basic execution environment」みたいな節に書いてある。
レジスタは拡張につぐ拡張があったので、理解するのにそれなりの時間がかかる。

アルファベットごとの命令表の、mov, add, sub, mul, div, imul, idiv,
push, pop, call, jmp, jcc 系を中心に見た後、ModRMについて書かれた節を見る。
最初は、16BIT/32BIT の ModRM、SIB について理解する。
その際、operand prefix, address prefix について理解する。
その後、64BIT の long mode, compatible mode の説明を読んだ後、
64BIT の ModRM, SIB について、REX prefix とまとめて理解する。


ちなみに、以下は後回しにする:
fadd, fsub, fmul, fdiv, fldp, fld, fstp, fld は、x87 FPU。
padd, psub は、MMX, addps, addss, subps, subss, mulps, mulss は、SSE系。

mm0〜mm7, xmm, ymm, zmm, に関する movxxxx も最初は無視。
これらの movxxxx は、アルファベット順の命令ごとについての書かれた章
のに解説が書かれているが、アラインだとかの説明が難しい。
実は、同じマニュアルセットの全然別の場所にこれらの movxxxx 命令の
説明が割りと平易な言葉で書かれているので参考になる。ただし、英語。
翻訳版の日本語だと余計に意味が分からないかもしれないの注意。

AVX系命令は、まず、VEX, EVEX prefix を読む。REX prefix が完全に理解
してないと理解は難しいと思う。
0260デフォルトの名無しさん
垢版 |
2018/09/27(木) 16:33:04.36ID:JRG0evD8
>>259
ちなみに、命令表は、

1. マニュアルの中心付近にアルファベット順に書かれているもの
2. ずっと後の付録の当たりに確か2進数の BIT 的に書かれているもの
3. マシン語から命令へ逆にたどれるもの

の3種類ある。

以上の命令表のうち、最初に読むべきなのは、上記の「1」のもの。
その命令表を見るための準備も必要。
マニュアルをよく探すと、/0〜/7 の意味、+b, +w, +d, +q の意味などが書かれた
部分がある。基本的には、そこを読まないとちゃんとした理解は出来ない。
それだけでなく、命令表も2部に分かれているような独特の読み方がある。それも、
上記の説明と同じような場所にまとめて出ている(分かりにくいが)。
(オペランドの種類を1つの表では表しにくいので、ポインタ参照のような感じで
記号で、後の表の行を指定するような感じになっている。)

REX prefixについては、AMD社のAMD64のManualも当然参考になる。

REX prefix は、色々と注意が必要で、細かい点を正確に理解するのは
しばらく時間がかかる。
0261デフォルトの名無しさん
垢版 |
2018/09/27(木) 16:36:18.33ID:qYKYy6B3
墓場に一番近いスレ
0262デフォルトの名無しさん
垢版 |
2018/09/27(木) 16:49:13.96ID:JRG0evD8
>>260
分かっているかもしれないが、x86系では、if()文に相当するものは、
基本的には、cmp aaa,bbb 命令で、(仮想的に)引き算をした後、
結果に基づいて、
zf, cf, sf, of(zero flag, carry flag, sign flag, overflow flag) など
のフラグ類に値が設定されて、そのあと、フラグ類に基づいて、
jz, jnz, jg, jge, jl, jle, ja, jae, jb, jbe などで jump (branch) する仕組み。

cmp命令は、ほとんど sub と同じだが、sub は、結果を destination
に実際に代入するのに対し、cmpは、結果はフラグ類以外にはどこにも
返さない。

subでも、フラグ類は設定されるので、上記の条件ジャンプは cmpと
全く同様に使える。実は、add や test, and, xor などでも、
条件ジャンプは行える場合がある。

整数で多倍長の加算を行うには、caryy flag を使って、add, adc を続けて行う。
減算の場合は、sub, sbb。

add ・・・
adc ・・・
adc ・・・
adc ・・・
・・・

みたいにすると、どれだけでも桁数は増やせる。

掛け算や、割り算の多倍長計算については、もっと数学的に行うが足し算と
引き算だけは、簡単に行える。
0263デフォルトの名無しさん
垢版 |
2018/09/27(木) 17:57:17.06ID:ry/jwNzc
そもそも>>1
>PICやH8を
などと書いてあるのに「組み込み用プロセッサなんて知らなくて当然だ」的な態度は回答者としてどうなんだ?
0264デフォルトの名無しさん
垢版 |
2018/09/27(木) 19:29:19.93ID:fZkL81UT
まずはCコンパイラにアセンブラ出力させて、
それを元に命令の動作をリファレンスマニュアルで確認していった方が楽なのでは?
いきなりマニュアルだけ読むだけだと大変だろうね
ちなみにC++よりもC言語の方がアセンブラ出力を読むのは簡単なはず
あと、Visual C++なら32bitのx86でやった方がいいよ
64bitのアセンブラ出力はそのままアセンブラでアセンブルできないはず
32bitならVisual C++のアセンブラ出力をアセンブラでそのままアセンブルできる
0265デフォルトの名無しさん
垢版 |
2018/09/27(木) 19:51:12.89ID:fZkL81UT
gccなら64bitでもアセンブラ出力できる
AVRを使ったことがあってgcc使ってたのならLinux上でgcc使ってみるのもあり
この場合、コマンドライン主体になるけどね
Linuxなら
objdump -M intel -d hogehoge
という感じで実行ファイルやオブジェクトファイルの逆アセンブルができる

gccでx86のアセンブラ出力をするときは-masm=intelのオプションを忘れずに
やり方はこんな感じ
gcc -S -masm=intel -o hogehoge.s hogehoge.c
このアセンブラリストを
as -a=hogehoge.lst -o hogehoge.o hogehoge.s
とアセンブルできる
これでできたオブジェクトファイルを
gcc -o hogehoge hogehoge.o
これで実行ファイルが完成

gdbではdisasで逆アセンブルできる
逆アセンブルする前にset disassembly-flavor intelを1回入力してやれば
それ以降の逆アセンブルがintel記法で出力される

最後に、WindowsとLinuxでは関数の呼び出し規約が違ったりするのをお忘れなく
0267デフォルトの名無しさん
垢版 |
2018/09/27(木) 20:02:31.89ID:fZkL81UT
x86のアセンブラで注意が必要なのは
例えば、
mov eax, data01
とあった場合、data01のメモリの内容がeaxに入る
決してdata01のアドレスではない
data01のアドレスを読み込みたかったら
mov eax, offset data01
こうすること
0269デフォルトの名無しさん
垢版 |
2018/09/28(金) 15:40:04.81ID:O5kQkBkV
lea だろう常考
0270デフォルトの名無しさん
垢版 |
2018/09/29(土) 06:54:45.13ID:31v81hqm
32bitでは
lea eax, hogehoge
よりも
mov eax, offset hogehoge
の方が命令が1バイト少なくなる

64bitでは
lea rax, hogehoge
だとアドレスはRIP相対の32itDISPになって7バイト
mov rax, offset hogehoge
だと64bitのimmを読み込むので10バイトになって3バイト長くなるけど
0271デフォルトの名無しさん
垢版 |
2018/09/29(土) 07:01:44.57ID:31v81hqm
gccやgasだとx86_64で64bit immを読み込む命令のニーモニックが違うんだよな
movabs rax, offset flat hogehoge
gasだとこうなるかな
0272デフォルトの名無しさん
垢版 |
2018/09/29(土) 09:36:52.97ID:31v81hqm
>>271
movabs rax, offset flat: hogehoge
でした
0273デフォルトの名無しさん
垢版 |
2018/09/29(土) 10:00:32.42ID:31v81hqm
Linuxでx86_64のgccでコンパイルしたものをとアセンブラのリンクする時に
lea rax, hogehoge
これや
mov rax, hogehoge
これをやるとリンク時にエラーが出るね

lea rax, hogehoge[rip]
mov rax, hogehoge[rip]
こうしないといけないみたい
0274デフォルトの名無しさん
垢版 |
2018/09/29(土) 12:31:21.31ID:1LSQxS0k
>>273
x64 独特の事情からかんがみて、言いたいことは分かってるつもりだが、
一応、MASM の元々の書き方の仕様では、C言語で言うと、

mov rax, hogehoe[rip]  ; rax = *(rip + &hogehoge)
mov rax, hogehoe     ; rax = *(&hogehoge)

の「意味」なので、本来は、働きが異なるのでその辺は注意を払う必要がある。

x64 だと、メモリオペランドでは、「絶対アドレス指定」より、
「rip 相対」が短いコードになり、なおかつその場合は、
disp 部分に 64BIT値が入れられないので色々と話が複雑になるけれど。

( gcc(gas)でどう意味に解釈されているかは知らないけど。 )
0275デフォルトの名無しさん
垢版 |
2018/09/29(土) 12:34:45.26ID:1LSQxS0k
>>274
元々の、masm の syntax 的には、
   mov rax,[addr]    ;絶対アドレス指定
と、
   mov rax,[rip + (addr - offset label1)]   ;相対アドレス指定
label1:

が rax に入る値が同じになるハズ。
0276デフォルトの名無しさん
垢版 |
2018/09/29(土) 12:40:11.70ID:1LSQxS0k
>>274
ちなみに、x86(IA32)モードでは、

[addr]

の ModRM のオペランドのマシン語 encode と全く同じ encode が、
x64(AMD64)では、

[rip + rel32]

になってしまって、しかも後者には、rel32 のための disp32 の4BYTE値が、
ModRM の直後に埋め込まれる仕様になっている。


これは、色々と誤解を招きやすい仕様で、初心者に混乱なく説明するのが難しくなってしまう。
0277デフォルトの名無しさん
垢版 |
2018/09/29(土) 13:18:43.07ID:31v81hqm
>>274
MASMだとx64で
mov rax, hogehoge
こう書くと
mov rax, [hogehoge+rip]
の意味になるよ
マシン語は48 8B 05 xxxxxxxxでRIP相対の32bitDISPの解釈になる

Linuxのgccやgasだと
mov rax, hogehoge
これが32bitの絶対アドレスと解釈される模様
マシン語は48 8b 04 25 xxxxxxxxと
スケールインデックスの基数を持たない32bitDISPになってしまってる
これだとRIP相対にならないのでリンク時にエラーになる
mov rax, hogehoeg[rip]
これだとマシン語は48 8b 05 xxxxxxxxとRIP相対の32bitDISPになる

Linuxのgccやgasで64bit絶対アドレス読み込みや64bit絶対アドレス指定のデータロードは別のニーモニックになる
movabs rax, offset flat: hogehoge
マシン語は48 b8 xxxxxxxxxxxxxxxx

movabs rax, hogehoge
マシン語は48 a1 xxxxxxxxxxxxxxxx
(64bit絶対アドレス指定のデータロードはraxのみ)
0278デフォルトの名無しさん
垢版 |
2018/09/29(土) 13:25:59.67ID:31v81hqm
ちなみにMASMで
mov rax, offset hogehoge
こう書くと
マシン語は48 b8 xxxxxxxxxxxxxxxx
となる
0280デフォルトの名無しさん
垢版 |
2018/09/29(土) 13:55:45.43ID:31v81hqm
そもそもMASMのx64版で
mov rax, [hogehoge+rip]

mov rax, hogehoge[rip]
こうするとエラーになるよ
0281デフォルトの名無しさん
垢版 |
2018/09/29(土) 14:34:50.49ID:1VwJZM7J
>>277
>MASMだとx64で
>mov rax, hogehoge
>こう書くと
>mov rax, [hogehoge+rip]
>の意味になるよ
>マシン語は48 8B 05 xxxxxxxxでRIP相対の32bitDISPの解釈になる


言いたいことが間違っているわけではないけど、厳密には、

MASMだとx64で
  mov rax, hogehoge
と書くと、
  mov rax, [rip + (offset hogehoge - offset label1)]
label1:


の「意味になる」。
0282デフォルトの名無しさん
垢版 |
2018/09/29(土) 14:36:51.71ID:1VwJZM7J
そもそも、IA32までは、jmp, call 以外ではRIP相対は無かったので、
RIP相対については、masm も gas も、今のところ書式(syntax)的に
無理がある気がする。
0283デフォルトの名無しさん
垢版 |
2018/09/29(土) 14:39:38.93ID:1VwJZM7J
つまり、今のところメモリオペランドの syntax に一貫性がなくなってきてしまっていると思う。
0284デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:05:27.10ID:31v81hqm
>>281
つっこむならMASMで試してからつっこめよ
そもそもripはundefined sysmbolになって使えないっての

あなたのつっこみは話がややこしくなるだけだよ
0285デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:07:28.65ID:1VwJZM7J
>>284
「意味」になるだけで、通じないことは知ってるよ。

そもそも、masm は [ ] の中に、offset hogehoge 書くと、その通りの
意味にはならないことがあるよ。
0286デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:08:54.79ID:31v81hqm
MASMは実用性を重視して
mov rax, hogehoge
こういう書式

gcc、gasはより厳密に
mov rax, hogehoge[rip]

あくまでそういう決まりごとってこと
書式は違ってくるが
そもそもVisual C++やMASMとgcc、gasでは違うところが多すぎるから問題ない
gccやgasではアセンブラはデフォルトではAT&T記法だしな
0287デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:10:56.60ID:31v81hqm
>>285
何、その意味不明な記述
[ ]の中にoffset入れるわけないだろ
そういう突っ込みはいいから。
あなたのつっこみは話をややこしくするだけだろ
0289デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:18:29.23ID:1VwJZM7J
>>287
C 言語での、*(&hogehoge) の MASM 版は、意味的には、

[offset hogehoge]

になって、ちょうどそれは、「hogehoge」 の意味に戻るはずなんだけど、
実際に masm でやってみると、変になる。記憶によると、masm では、

[hogehoge]

が hogehoge と書いたのと同じ意味になったはず
(論理的にはそんなはずは無いんだけども)。
0291デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:23:02.46ID:P6L1chXc
C言語との対応関係も知らずにアセンブラ語ってたとは驚き
で、また火病って連投してるね
0293デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:29:01.40ID:31v81hqm
>>289
あなたの書いてることの意味はもともとわかってるっての
MASMではと書いておきながらMASMで通らない命令を書いて人の発言に横槍入れて
したり顔してるのがおかしいってだけ
0295デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:37:30.74ID:31v81hqm
>>291
もともとわかってることなのに
実際のアセンブラでアセンブルできない命令を書いて因縁つけてスレを混乱させてるのは
ID:1VwJZM7Jの方だぞ
0297デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:41:02.87ID:31v81hqm
ID:1VwJZM7Jは論理的にとか書いてるが
実際のアセンブラの仕様を無視して、アセンブラで通らない命令書いてドヤ顔してるやつ
コンピュータなんて論理的におかしい命令とか普通にあるだろ
アスペはそういうのが我慢ならないらしい
0299デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:46:13.22ID:31v81hqm
>>298
あなたもx86_64のアセンブラの仕様関して全く理解してないのはわかった
あなたもしたり顔で語るなよ
ここに書かれてる命令を実際にアセンブルしてその結果を見れば誰が正しいことを言ってるかわかるはず
0300デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:50:43.93ID:31v81hqm
>>298

>>280にも書いたが
MASMでは
mov rax, hogehoge[rip]
こんな書き方や
mov rax, [hogehoge+rip]
こんな書き方をすると
error A2006:undefined symbol : rip
とエラーになるんだよ
0302デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:52:36.05ID:IuTgmxg/
論理的におかしい命令なんかない
処理されるまでの過程は別にして計算機は命令されたとおりに動く

処理結果がおかしいのはキミラのオツムの問題

そもそもアセンブラなんか
キャッシュミスをできるだけむりやり回避するためにインラインアセンブラ書くとか
非常に明確な理由がないかぎりまず使われることなんかまずない

つまりココではアホ同士がアホなことでもめてる
0303デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:54:58.28ID:31v81hqm
>>301
> x64 独特の事情からかんがみて、言いたいことは分かってるつもりだが、
> 一応、MASM の元々の書き方の仕様では、C言語で言うと、
>
> mov rax, hogehoe[rip]  ; rax = *(rip + &hogehoge)
> mov rax, hogehoe     ; rax = *(&hogehoge)
>
> の「意味」なので、本来は、働きが異なるのでその辺は注意を払う必要がある。

そもそもMASMでは
mov rax, hogehoe[rip]
こんな記述は未サポート

mov rax, hogehoe
これが*(rip + hogehoge)の意味
0304デフォルトの名無しさん
垢版 |
2018/09/29(土) 15:57:13.97ID:31v81hqm
>>302
アスペ君は
mov rax, hogehoge
これが*(hogehoge + rip)の意味になるところが気に入らなくて突っ込みいれてるだけ
でも、実際に仕様なのだからしょうがないってこと
0305デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:01:34.18ID:P6L1chXc
>>273みたいなこと書く奴が「理解できてる」はずないだろw
今回も「リンク時にエラーが出る」とか言ってさ
0306デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:06:06.66ID:31v81hqm
>>305
MASMでは
mov rax, hogehoge
こう書くのが正解なんだが
Linuxでgccとgas使ってプログラム組むと
mov rax, hogehoge
これを書くとリンク時にエラーが出る
理由は>>277に書いてある

Linuxでgcc、gasでは
mov rax, hogehoge[rip]
これでMASMのときのmov rax, hogehogeと同じマシン語が生成されえる
コンパイラやアセンブラが違えば仕様が違うってこと
0307デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:18:56.60ID:P6L1chXc
32bitではきちんと理解してなくてもなんとかなったってだけなの
x64知らないなら出てこなきゃいいのに
0308デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:24:58.15ID:31v81hqm
>>307
x86_64をわかってないのはあなただろ
MASMでは
mov rax, hogehoge
こう書く仕様だっての

gcc、gasでは
mov rax, hogehoge[rip]
こう書くのが仕様

ただそれだけ
マシン語ではどちらも48 8b 05 xxxxxxxxとRIP相対の32bitDISPになる
0309デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:32:57.40ID:31v81hqm
offsetを使ったものも

MASMでは
mov rax, offset hogehoge
これでマシン語は48 b8 xxxxxxxxxxxxxxxxと64bit絶対アドレスになる

gcc、gasでは
movabs rax, offset flat: hogehoge
これでマシン語は48 b8 xxxxxxxxxxxxxxxxと64bit絶対アドレスになる

leaを使うと
MASMでは
lea rax, hogehoge
これでマシン語は48 8d 05 xxxxxxxxとRIP相対32bitDISPになる

gcc、gasだと
lea rax, hogehoge[rip]
これでマシン語は48 8d 05 xxxxxxxxとRIP相対32bitDISPになる
0310デフォルトの名無しさん
垢版 |
2018/09/29(土) 16:43:03.59ID:31v81hqm
x86_64のRIP相対アドレッシングは歴史的には
32bitの時の32bit絶対アドレッシングの仕様を変更してRIP相対をねじ込んだ形だからね
アセンブラの記述的に、論理的におかしくてもしょうがないんだよ
論理的なものよりも実用性を重視したのがMASM
より論理的に厳密にしたのがgasということだろうな
0311デフォルトの名無しさん
垢版 |
2018/09/29(土) 17:11:34.41ID:kF9GSkBg
ちょっと質問なんだけど
dataセクションは32bitアドレス内にないとアクセスできないってこと?

extern int aaa[10];
int bbb (int i) {return aaa[i];}

このコードがこんな感じになってたんだけど

00000000004011a0 <bbb>:
4011a0: 48 63 ff movslq %edi,%rdi
4011a3: 8b 04 bd 40 40 40 00 mov 0x404040(,%rdi,4),%eax
4011aa: c3 retq

aaaがdataセクションの0x404040にあったからこうやってアクセスできたけど
32bit超えてたらこの命令は翻訳できない?
0312デフォルトの名無しさん
垢版 |
2018/09/29(土) 17:23:41.07ID:31v81hqm
>>311
アセンブラのみではそういうことはないけど、C言語とリンクする場合はそうなるね
64bitでも通常はグローバル変数などのシンボルやジャンプ先のラベルは32bitを前提としてコンパイルされている
x86_64だとRIP相対の32bitDISPで届かないところにはアクセスできない
他のCPUでも似たようなもの

Windowsだと回避方法はない
LinuxだとHPCなどで-mcmodel=mediumを指定することで回避できる方法はあるけどね
0314デフォルトの名無しさん
垢版 |
2018/09/29(土) 17:35:24.77ID:31v81hqm
>>311を俺の環境でgccでコンパイルしてみたらこうなった
オブジェクトファイルなのでアドレスは00 00 00 00のまま
gccのバージョンは7.3.0

0000000000000000 <bbb>:
0: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # 7 <bbb+0x7>
7: 48 63 ff movslq %edi,%rdi
a: 8b 04 b8 mov (%rax,%rdi,4),%eax
d: c3 retq
0316デフォルトの名無しさん
垢版 |
2018/09/29(土) 17:37:16.65ID:31v81hqm
AT&Tニーモニックの貼ってしまった

Intelニーモニックはこっち
0000000000000000 <bbb>:
0: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 7 <bbb+0x7>
7: 48 63 ff movsxd rdi,edi
a: 8b 04 b8 mov eax,DWORD PTR [rax+rdi*4]
d: c3 ret
0317デフォルトの名無しさん
垢版 |
2018/09/29(土) 17:42:37.03ID:kF9GSkBg
一旦axに入れてるんだ
そっちの方が遠くまでアクセスできそう
俺のはlinuxだからかな
gccは8.2.0だけど7.3でも>>311のようになりそう
0319デフォルトの名無しさん
垢版 |
2018/09/29(土) 18:29:50.29ID:kF9GSkBg
7.3でも5.3でも>>311のになった
configure 設定: ../gcc-7.3.0/configure --prefix=/usr --libdir=/usr/lib64 --mandir=/usr/man --infodir=/usr/info --enable-shared
--enable-bootstrap --enable-languages=ada,brig,c,c++,fortran,go,lto,objc --enable-threads=posix --enable-checking=release
--enable-objc-gc --with-system-zlib --enable-libstdcxx-dual-abi --with-default-libstdcxx-abi=new --disable-libunwind-exceptions
--enable-__cxa_atexit --enable-libssp --enable-lto --disable-install-libiberty --with-gnu-ld --verbose --with-arch-directory=amd64
--disable-gtktest --disable-multilib --target=x86_64-slackware-linux --build=x86_64-slackware-linux --host=x86_64-slackware-linux
スレッドモデル: posix
gcc バージョン 7.3.0 (GCC)

configure 設定が違うのかな
0320デフォルトの名無しさん
垢版 |
2018/09/29(土) 18:31:39.06ID:1VwJZM7J
>>303
>mov rax, hogehoe
>これが*(rip + hogehoge)の意味

それは明らかに間違っているよ。

正しくは、>>281 のように、

MASM だと 64bit mode で
  mov rax, hogehoge
と書くと、
  mov rax, [rip + (offset hogehoge - offset label1)]
label1:

の「意味」になって(ただし、実際の masm ではこの書き方はエラーになるはず)、

C言語で書けば、
rax = *( rip + (&hogehoge - &label1) )
label1:

の「意味」になる。
0321デフォルトの名無しさん
垢版 |
2018/09/29(土) 18:37:57.88ID:1VwJZM7J
>>320
理解のポイントは、(64BIT)命令ポインタ rip は、CPUが、ModRM
の間接(メモリ)オペランドを解釈する時には、命令の直後の
アドレスを指しているかのようにみなされて、丁度、

rip = offset label1

または、

rip = &label1


であるかのように解釈されるということ。
0322デフォルトの名無しさん
垢版 |
2018/09/29(土) 18:52:23.15ID:31v81hqm
>>320
RIP相対32bitDISPって書いてるんだからわかってるんだよ、そんなこと
わかりきったことをしたり顔で書いてんじゃねーよ
0323デフォルトの名無しさん
垢版 |
2018/09/29(土) 19:02:53.64ID:31v81hqm
>>319
自分でビルドしたやつじゃないけど
gcc -vをやると
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.3.0-27ubuntu1~18.04'
--with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++
--prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared
--enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie
--with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror
--with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic
--enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
0325デフォルトの名無しさん
垢版 |
2018/09/29(土) 19:30:06.39ID:P6L1chXc
MASMはデフォルトがrip相対だからな
offset演算子使った段階でアドレスではなくただの数値になってるのが理解できんのか
だから絶対アドレスになんだよ
0326デフォルトの名無しさん
垢版 |
2018/09/29(土) 19:42:48.86ID:31v81hqm
>>325
ただの数値じゃないぞ
だって再配置される時に64bitの絶対アドレスが再配置されたアドレスに置き換わる
だからただの数値じゃない、64bit絶対アドレスとして認識されてるはず
0327デフォルトの名無しさん
垢版 |
2018/09/29(土) 19:54:13.97ID:31v81hqm
変な突っ込みする人がいるから書くが
CPUの命令的にはx86_64で
mov rax, offset hogehoge
これは64bitのimmを読み込むマシン語に変換される
要するにただの64bitの数値を読み込む命令
マシン語は48 b8 xxxxxxxxxxxxxxxx
ただ、アセンブラはちゃんと64bit immの部分が64bitの絶対アドレスということを認識してる
だから再配置された時に64bit絶対アドレスが再配置後のhogehogeのアドレスに置き換わる
0328デフォルトの名無しさん
垢版 |
2018/09/29(土) 20:19:25.44ID:31v81hqm
こんなことみんな知ってるとは思うが
実際に64bit絶対アドレスが確定するのはプログラムがメモリ上にロードされる時
このときに、絶対アドレスなどの情報が配置されるアドレスによって正しい値に書き換えられる
0329デフォルトの名無しさん
垢版 |
2018/09/29(土) 21:07:16.90ID:P6L1chXc
そもそも
lea rax, [hogehoge]
って書いときゃNASMでも通るのに
>data01のアドレスを読み込みたかったら
>mov eax, offset data01
>こうすること
なんて教えようとするのかね?
0331デフォルトの名無しさん
垢版 |
2018/09/30(日) 00:47:29.69ID:KtGjBt6/
Microsoft (R) Macro Assembler (x64) Version 12.00.40629.0
mov al, hogehoge
mov al, [hogehoge]
mov rax, offset flat:hogehoge ; error A2006:undefined symbol : flat
lea rax, [hogehoge]
lea rax, offset flat:hogehoge ; error A2006:undefined symbol : flat
lea rax, hogehoge

14.00.24210.0でも同じだな
0332デフォルトの名無しさん
垢版 |
2018/09/30(日) 00:54:08.42ID:KtGjBt6/
clが吐いた.codでは
lea rax, offset flat:hogehoge
みたいな表記になってるけど、ml64は受け付けない
0333デフォルトの名無しさん
垢版 |
2018/09/30(日) 01:03:38.57ID:KtGjBt6/
mov eax, offset hogehoge
とやってもエラーも出ないんだよね 当然だけど
0000001A 48/ B8 0000000000000000 E mov rax, offset hogehoge
00000024 B8 00000000 E mov eax, offset hogehoge
0334236
垢版 |
2018/09/30(日) 01:18:13.92ID:PppEulsk
なんか説明が不適切だったせいで偉いことになってしまった・・・すまん

とりあえずAMD64のプログラミングマニュアルとIA32/EM64Tの日本語プログラミングマニュアルはダウンロードしてあります

やりたいことは演算ではなくて特殊?な例外処理です。C風に書くと
unsigned int *a;
unsigned int b;
&a = 0x00001000; // アドレスをセット
*a = 0x00888888; // 0x00001000へ値を書き込み
b = *(&a + 1); // 0x00001004の値を読み出し。読み出される値は0x00001000の値に0x0100を加算した物
// bの中身は0x00888988
みたいな感じかな。メモリの読み書き動作に任意の処理を挟みたいです。自分なりにこのような動作をさせる方法を考えた結果
・該当する仮想アドレスにメモリを割り当てない
・アクセスすると発生するページフォールトをハンドリングする
・ハンドラ中で値の処理とアクセス元のコードが行うつもりだった読み書き動作もする
・ページフォールトを発生させた次の命令から実行を再開する
となったのですがこれらを高級言語のみで実装するのは無理そうな気がするのでアセンブラを読み書きできる必要があるかなと・・・
各OSごとの例外処理がらみの情報も必要ですがこの辺もなかなか見つけられないです
0335デフォルトの名無しさん
垢版 |
2018/09/30(日) 04:51:47.08ID:fqhkGGw5
>>322
64bitのcl.exeが吐き出すアセンブラ出力はml64.exeでそのままではアセンブル通らないよ
何箇所か、修正が必要になる
ちなみに32bitのcl.exeが吐き出すアセンブラ出力はそのまま32bitのml.exeでアセンブルできる



>>333
mov eax, offset hogehoge
これをx64用のml64.exeでアセンブルしてもエラーは起きないが
リンク時にこのエラーが出るよ
error LNK2017: 'ADDR32' relocation to
'hogehoge' invalid without /LARGEADDRESSAWARE:NO
LINK : fatal error LNK1165: link failed because of fixup errors
64bitのアドレスを32bit絶対アドレスに切り詰めてるのだから当たり前だけど

mov rax, offset hogehoge
これは全く問題ない
アセンブルもリンクも正常に行われるし、正常にプログラムを実行できる
0336デフォルトの名無しさん
垢版 |
2018/09/30(日) 17:26:28.46ID:KtGjBt6/
>>335
NASM(bits64, default rel)だとエラーになるよ
mov rax, offset hogehoge ; error: comma, colon, decorator or end of line expected after operand
lea rax, hogehoge ; error: invalid combination of opcode and operands
lea rax, [hogehoge] ⇒ 488D05

mov al, hogehoge ⇒ B0
にアセンブルされたりもするけど

MASMでもlea rax, [hogehoge]やmov al, [hogehoge]はNASMと同じマシン語になるはず

Windows 64bitはrip相対使ってるのに、MASMで簡単に絶対アドレスが登場するのがおかしいと思わないのかね
0337デフォルトの名無しさん
垢版 |
2018/09/30(日) 21:29:51.77ID:KtGjBt6/
>>334
いまいちやりたいことが分からないんだけど、Windowsでアクセス違反をハンドリングするのは
https://docs.microsoft.com/ja-jp/windows/desktop/Memory/reserving-and-committing-memory
が参考になるんじゃないかな
__except()のフィルタ関数でアクセス違反をチェックして、対象範囲のアドレスだったらVirtualAllocで
コミットして__except()にEXCEPTION_CONTINUE_EXECUTION返せば再実行される
対象範囲外のアドレスはEXCEPTION_CONTINUE_SEARCHを返す必要がある
メモリは事前に予約してないと例外から回復できないみたい

構造化例外処理は
http://www.ne.jp/asahi/hishidama/home/tech/vcpp/seh.html
https://msdn.microsoft.com/ja-jp/library/swezty51.aspx
を読んでみて
0338デフォルトの名無しさん
垢版 |
2018/10/01(月) 04:48:19.14ID:gNvpqBnl
>>336
LinuxのNASMとMASMは構文違うよ

NASMだと
mov rax, hogehoeg
マシン語は48 b8 xxxxxxxxxxxxxxx
これでraxにアドレスが入る

WindowsのMASMだと
mov rax, hogehoge
マシン語は48 8b 05 xxxxxxxx
hogehogeのメモリの内容がraxにロードされる
MASMの場合、
mov rax, offset hogehoge
これだとマシン語は48 b8 xxxxxxxxxxxxxxxx
これにしないとNASMのmov rax, hogehogeと同じマシン語にならない
0340デフォルトの名無しさん
垢版 |
2018/10/01(月) 05:51:48.63ID:gNvpqBnl
>>336
RIP相対32bitdispだとアクセスできない場合が出てくる
シンボルがRIP相対2GBに制限されるなどはあくまでCコンパイラの制限であって
アセンブラはその制限を受けない
実際にWindowsのEXEファイルは64bit絶対アドレスに対応してて
きちんと再配置してくれるわけだし
0341デフォルトの名無しさん
垢版 |
2018/10/01(月) 06:38:07.64ID:Z1gvrlLR
これこそアスペって奴だよな
質問とは関係ないCPU持ち出して勝手に「語り」をはじめたり、32bitでは1バイト短くなるだの
実用的には0.001%程度しか影響なさそうな絶対アドレスの方が速いだの、C/C++とリンクして使うのが
普通なのに「シンボルがRIP相対2GBに制限されるなどはあくまでCコンパイラの制限であってアセンブラはその制限を受けない」とか
初心者そっちのけで有害としか思えないような方法垂れ流したりと、他人の迷惑とか全く考えられないんだから

初心者にはMASMとNASMで同じように使えればそれで十分
完全に同じマシン語になるかどうかなんて知るか
特に絶対アドレスなんてWin64には不要と考えるべき
初期化領域以外の動的確保されたメモリはポインタ経由のアクセスが基本なんだから
0342デフォルトの名無しさん
垢版 |
2018/10/01(月) 06:45:27.19ID:Z1gvrlLR
>>334
こういう状態なんで、334は全く悪くないから気にしなくていいよ

アクセス違反を検出して対応するのは、使ってみたいところがあったのでちょうどいい機会だった
一応自分の書いたテストプログラムを上げとくね
https://pastebin.com/b5gZXxCF
0343デフォルトの名無しさん
垢版 |
2018/10/01(月) 06:51:19.23ID:gNvpqBnl
>>341
>>338が理解できないのか?
LinuxのNASMとWindowsのMASMは根本的に文法が違う
同じようにはプログラミングできないっての

MASMではMS-DOSの頃から伝統的に
mov ax, hogehoge
これをやるとhogehogeのメモリの内容をaxに読み込む
はじめて読むMASMにもそう書いてあるよw
0344デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:02:13.01ID:gNvpqBnl
はじめて読むMASM
79ページ目
 データラベルは、マシンご命令のニーモニックのなかで、データを格納す
るメモリを参照するために使用することができます。次の図3−10をみてく
ださい。この図では、違いを対比させるために次節で解説するOFFSET擬似
命令の役割を併せて図解してあります。
 この場合、MESSAGEというデータラベルは01C3Hというアドレスに対応
しています。コードラベルの場合は、ラベル名がアドレスそのものと対応し
ていましたが、データラベルの場合にはちょっと違います。このことは重要
ですからよく覚えておいて下さい。
 たとえば、SYMDEBのようにアドレスを直接数値で指定する場合、そのア
ドレスのメモリの内容を参照するには、
 MOV DX, [01C3H]
のようにアドレスを[]で囲みます。これに対し、アセンブラのソースプロ
グラムでは、
 MOV
0345デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:04:42.69ID:gNvpqBnl
はじめて読むMASM
79ページ目
 データラベルは、マシンご命令のニーモニックのなかで、データを格納す
るメモリを参照するために使用することができます。次の図3−10をみてく
ださい。この図では、違いを対比させるために次節で解説するOFFSET擬似
命令の役割を併せて図解してあります。
 この場合、MESSAGEというデータラベルは01C3Hというアドレスに対応
しています。コードラベルの場合は、ラベル名がアドレスそのものと対応し
ていましたが、データラベルの場合にはちょっと違います。このことは重要
ですからよく覚えておいて下さい。
 たとえば、SYMDEBのようにアドレスを直接数値で指定する場合、そのア
ドレスのメモリの内容を参照するには、
 MOV DX, [01C3H]
のようにアドレスを[]で囲みます。これに対し、アセンブラのソースプロ
グラムでは、
 MOV DX, MESSAGE
とします。このことからわかるように、データラベルはラベルに対応するア
ドレスそのものではなく、そのアドレスが示すメモリの内容を表します。
つまり、データラベルそのものを指定すると、アドレスの値を転送したり演算
したりする命令ではなくて、メモリに対して転送や演算を行う命令になりま
す。もう1度図3−10を見てじっくり確認してください。

こう書かれてる
0346デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:10:06.78ID:gNvpqBnl
82ページ目

3.6
OFFSET演算子とPTR演算子
OFFSET演算子
[書式] OFFSET ラベル名

データラベルをニーモニック中で使用すると、データ部分のアドレスでは
なく、データを格納したメモリの内容を表しますが、そのメモリのアドレス
はどうやって表すのでしょうか。図3−10で図解してあるので解説するまでも
ありませんが、データラベルに対応するアドレスは、次のように表します
 OFFSET データラベル
 OFFSET演算子は、ラベルに対して使用する演算子です。ラベルの前にこ
の演算子を付けると、ラベルに対応するアドレスを表す値となります。
 例題のプログラムでは図3−11の部分で使われています。これは画面に出
力するメッセージが格納されているアドレス値を、データとして定義してい
る例です。



MASMの文法は16bitの頃から一貫してる
みんなはじめて読むMASMからやりなおしだな
0347デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:41:22.29ID:Z1gvrlLR
>>343
MASMでもmov al,[hogehoge]やlea rax,[hogehoge]が使えて、NASMと「同じ動作」が期待できて、
「根本的に」書き換えなくても疑似命令やマクロとかを書き換えれば移植できるってのがポイントで
NASMはLinux他とWindowsみたいなマルチプラットフォームのプロジェクトでよく使われてるから
あんたみたいなmov al,hogehogeやり方でNASMに移行すると変なバグに悩まされる可能性があんだよ
特にmov al,hogehogeがイミディエイトでアドレスの一部がコードされるのが酷い

SYMDEBで括弧で括るってのはイミディエイトと区別付かないからそうなってるんだろ
これはNASMで括弧で括るのと同じこと
時代遅れになった本の内容なんてどうでもいい
括弧で括らない表記は、8080時代を踏襲してるのか、インラインアセンブラでのCの変数参照と統一感があるってところだろう
これならNASMで異なる動作にならない方が無難

こっちが言いたいのは、初心者に有用なことが書けないなら「出てくんな」ってことだけ
0348デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:55:48.93ID:gNvpqBnl
>>347
それは自分だけで書いたコードを読むだけならいいが
他人が書いたコードやコンパイラが吐き出したコードを読むのにはそれは通用しない
0349デフォルトの名無しさん
垢版 |
2018/10/01(月) 07:57:49.96ID:gNvpqBnl
それにNASMで慣れるとgccでインラインアセンブラを使うときに困る
gccはx86_64でもインラインアセンブラを扱えるのに
NASMの文法はgccのインラインアセンブラでは通用しないぞ
0350デフォルトの名無しさん
垢版 |
2018/10/01(月) 08:10:48.59ID:gNvpqBnl
多くの人がOFFSET演算子に対する理解がないようだから書いただけなのに
猛烈に反発してくる変な人がいるだけ

gccでは-mcmodel=largeのオプションを付けてコンパイルすると
movabs rax, offset flat: hogehoge
のような表現がよく出てくる
64bit絶対アドレスを扱うには必ず必要になってくる
0351デフォルトの名無しさん
垢版 |
2018/10/01(月) 09:35:33.25ID:Yquio+NL
>>341
アセンブラは、かなり細かいことを理解して無いと使いこなせないかもしれないよ。
それが C/C++ などとは違う点。

ちゃんと、リストファイルを見て、Intel の Instruction 表と照らし合わせて
どの命令が出力されているかを確認し、さらに、OBJやEXEファイルを逆アセンブル
してみて、さらにさらに、ローダーが実際にどのようにロードしたかをデバッガ
で確認する、などをちゃんとしないと、うまくいかないかもしれない。

実際、純正の Visual Studio が出したアセンブリソースが、masm で通らない
などという現象が確認されている事からしても、色々と確認作業が必要だと
思う。

自分はアセンブリ経験が豊富だが、上記のような確認作業をかなり積んだから
こそ使えていたと思う。

アセンブラの出力は、バージョンによっても違っていることがあるかも
知れないし、64BITモードでは、同じニモニックでも異なるマシン語を
出力することもありえる。

さらに言うと、アセンブラ自体が非常に困った仕様になってしまっていることもあり得る。

もともと、アセンブリ言語は、初心者が混乱無く使えるようにはなってないという側面もある。

失礼かもしれないけど、他の言語で豊富な経験を積んで、なおかつ、地頭のいい人限定だよね、もともと。
0352デフォルトの名無しさん
垢版 |
2018/10/01(月) 09:38:14.45ID:Yquio+NL
あと、一度実験した内容を正確に覚える記憶力も必要。

本で書かれていることと実際が違っていることは良くある。
0353デフォルトの名無しさん
垢版 |
2018/10/01(月) 10:13:48.86ID:Yquio+NL
>>334
例外処理については、詳細な文献と実験調査を行ったことがある。

文献だけでは不十分で、コードをフックするような仕組みによって実験しないと分からない。

教えることは出来るが、ここでは馬鹿にされるだけなのですまんが答えられない。
0359デフォルトの名無しさん
垢版 |
2018/10/02(火) 08:43:48.77ID:+JdY6jxX
ただ、例外のハンドリングはできても、処理を続行するのは難しいね
EXCEPTION_CONTINUE_EXECUTION を返すと処理は続行されるけど
例外が発生するところから続行されるからね
例外が発生したところの次の命令から続行されるわけじゃないからね
0361デフォルトの名無しさん
垢版 |
2018/10/02(火) 18:27:14.93ID:6jgE/r0r
アセンブラが難しすぎて読めません
https://gyazo.com/ba3099329df9872df87fa3c35ff13384
これはFPSの弾数周辺のアセンブリなんですが、どういう処理をしてるのか全く分かりません
どういう風に読んでいけば理解できるのか?ヒント下さい
ニーモニックは何となく分かるんですけど・・
0362236
垢版 |
2018/10/02(火) 23:02:45.96ID:XopDtnD7
ありがとう。やりたいことはメモリマップドI/Oのエミュレーションです。なので呼び出し元のコードはなるべく細工したくありません

例外ハンドラでメモリを確保してしまうと2回目以降や隣接するアドレスのアクセス時に例外が発生しなくなってしまうので避けたいです
あとWindowsで>>334をやろうとした場合0x00001000から8Byteをあける必要がありますが、そのアドレスへデータをロードしないよう
MSVCのリンカへ指示する方法がわかりません
ldやlldなどであればリンカスクリプトで指示できるらしいのですが・・・(OSの候補にLinuxやFreeBSDがいる理由の一つです)

呼び出し元のコードに細工をすれば例外なんてめんどくさい物を使わずにすみますが、エミュレートしないケースの
オーバーヘッドを完全になくせるか心配です。コンパイラの最適化でインライン展開とデッドコード削除が約束されるなら
そっちの方が遙かに楽ですが・・・
0363デフォルトの名無しさん
垢版 |
2018/10/03(水) 00:49:48.02ID:/WqVKxM1
>>362
例外機構を使わずに、以下のような方法も場合によっては使える:

1. C++ の演算子の overload を使う方法。
2. Win32のメモリマップド I/O 機能を使う方法。



>あとWindowsで>>334をやろうとした場合0x00001000から8Byteをあける必要がありますが、
>そのアドレスへデータをロードしないよう
>MSVCのリンカへ指示する方法がわかりません

これは、VitualAlloc() で、0x1000 からの 1page(4096 バイト)をアクセス禁止の page に
すると可能。

ただし、8 バイト以外の部分もアクセス禁止になるので、その部分でも、例外ハンドラ
が起動してしまうので、その部分についての処理も例外ハンドラに書くようにする。
0364デフォルトの名無しさん
垢版 |
2018/10/22(月) 19:17:19.32ID:3rTgJh0a
最近CASLU覚えた後、実際のマイコンのアセンブリ言語覚えたくてルネサスのRL78も覚えたんだけど(PICはCASLU以前から覚えてはいた)、
x86とZ80を合わせたようなニーモニックだけかと思ったらAをR0、XをR1って別名に出来たりAXがRP0に出来たり、GR0、GR1って書くCASLUにニーモニックが似てるんだが。。。

これってもしかして癒着とかじゃあるまいな。
(逆にルネサスがCASLUに寄せた可能性も微レ存)

日本車に使われてるらしいし、自動車は国の基幹産業だし(つまりルネサスのお得意様は日本の自動車メーカー)、あり得なくはない。
0366デフォルトの名無しさん
垢版 |
2018/10/23(火) 14:50:58.07ID:yFsvvFWj
病院逝け
0369デフォルトの名無しさん
垢版 |
2018/11/30(金) 09:46:12.16ID:+k7v6spR
アセンブラの勉強始めていきなり躓いてるのですが、オペランドの記述で
r/m32やimm32やr32やm32って何の略なんですか?
検索しても命令一覧表ばかり引っかかって・・(;´д`)
0375デフォルトの名無しさん
垢版 |
2018/12/02(日) 03:55:19.52ID:5vpsWzUl
>>370
>>371
ありがとうございます!
0376デフォルトの名無しさん
垢版 |
2018/12/02(日) 13:54:11.82ID:vFBVENFT
LLVM 豆知識。
getelementptr には、似て非なるものが二種類ある。命令タイプと、定数タイプ。
後者は、他の命令のオペランドで用い、括弧でくくるような書き方をする。

仮想レジスタ %n に、整数定数を代入する命令が無い。
それで困った場合は、
 %10 = add i32 定数値, 0
などとすると良い。同様にポインタ定数も直接は代入できないが、
 %10 = getelementptr TYPE, TYPE * アドレス定数, 0
などとすれbな代入できる。
0377デフォルトの名無しさん
垢版 |
2018/12/02(日) 14:03:34.88ID:vFBVENFT
記憶に頼って書くと、

【命令タイプ】
%n =getelementptr TYPE, TYPE * 値, i32 idx1, i32 idx2, ・・・

【定数タイプ】
getelementptr (TYPE, TYPE * 値, i32 idx1, i32 idx2, ・・・)


getelementptr の他に、bitcast, itoptr, ptrtoi, ftoi, itof, zext, sext にも
全く同様に命令タイプと定数タイプがある。

この事は、Reference Manual には分かりやすくはかかれてないかも知れない。


また、話は変わるが、getelementptr は、配列のような概念を使うので、
アセンブラに慣れた人が、それを使うのが面倒な場合は、bitcast で i8* 型に cast
して計算する方法もある。

TYPE *ptr; に対し、

%R1 = bitcast TYPE * ptr to i8*
%R2 = getelmentptr i8* %R1, offset
%R3 = bitcast i8 * %R2 to TYPE*

とすれば、offset には、sizeof(TYPE) とは全く無関係の
バイト単位のオフセット値を指定できる。
0378デフォルトの名無しさん
垢版 |
2018/12/02(日) 14:16:20.44ID:vFBVENFT
記憶に頼って書く。

【getelementptr 豆知識】

getelementptr は、複雑なことをしているように見えるが、
 %n = getelementptr TYPE, TYPE * ptr, i32 idx
は、C 言語で書くと、
TYPE  ptr;
に対し、
%n = &(ptr[idx]);
を計算しているに過ぎない。

idx が2つ以上になって、
 %n = getelementptr TYPE, TYPE * ptr, i32 idx1, i32 idx2, i32 idx3
となった場合は、たとえば、TYPE が (n次元)配列の場合は、

%n = &(ptr[idx1][idx2][idx3]);

と同じ。覚えておくことは、アドレス演算子「&」が、最後にだけ付くということ。
この規則は構造体が中に含まれている場合でも全く変わらない。
0379デフォルトの名無しさん
垢版 |
2018/12/02(日) 14:24:12.50ID:vFBVENFT
言いたいことは変わらないが、TYPE が3次元配列の場合には、
TYPE *ptr; とは、厳密には、
ELEMTYPE (*ptr)[a][b][c];
となってるのだから、やりたいことは、
 %n = &(ptr[0][idx1][idx2][idx3]);
となる。だから、厳密に言うと、
idx を1つ増やす必要があり、
 %n = getelementptr TYPE, TYPE * ptr, i32 0, i32 idx1, i32 idx2, i32 idx3
となる。

規則性は、よく考えると分かる。
0381デフォルトの名無しさん
垢版 |
2018/12/08(土) 22:09:51.24ID:NuFUG+1u
LLVMのフロントエンドとバックエンドの自由度は極めて高い。CPUどころかGPUまである
ということはアーキテクチャAの実行イメージを入力に、アーキテクチャBの実行イメージを出力することも出来そう

と妄想した
0382デフォルトの名無しさん
垢版 |
2018/12/11(火) 15:12:16.55ID:TeIOtXwo
>>381
・Windows の EXE の場合、IAT、ILT、THUNK、DLL の名前解決などの LLVM への
 置き換えが果たして可能かどうか。これに関してはもしかしたら難しいかもしれない。

・COFF EXE の場合は可能かもしれないが、データ領域とコード領域を絶対に間違いなく
 区別する必要も有る。
0383381
垢版 |
2018/12/11(火) 17:56:58.27ID:8tcWxISv
>>382
そういう動的な処理の多いシステムは難易度が高いと思うので、ゲーム機のROMイメージを別のプラットフォームで
実行できる実行イメージに出来ないかなと思った。一般的なエミュレータより高効率で動作させられるはず

と妄想した
0384遠隔 MIPS フラッシュ書き込みテスト実験中
垢版 |
2019/02/23(土) 13:51:34.34ID:RfpPY2e5
MIPS アセンブラ初心者なんだけどおせーて?

asm volatile (“di %0” :“=r” (status));

って 割り込みを拒否して さらにstatusに現在の割り込み設定を退避させてるって意味でええの?
0385デフォルトの名無しさん
垢版 |
2019/02/24(日) 09:52:41.67ID:pcDSz9Pr
>>384
日本だと、8080, Z80, 6804(?), 68000, 8086, 80386(IA32) なら
答えられる人は少数なりにもある程度いるが、MIPSは難しいかもね、人数的に。
0386デフォルトの名無しさん
垢版 |
2019/02/24(日) 09:54:36.33ID:pcDSz9Pr
誤:6804
正:6809

多分、日本のパソコン文化の主流は、8080, Z80, 8086, 80386(IA32) だったと
思う。書くと反感買うと思うけど、少数派として、6809, 68000 があった、
という認識。
0388デフォルトの名無しさん
垢版 |
2019/02/24(日) 11:13:53.47ID:12/s8ZEO
>>385
そうなんだ

システムのプログラムフラシュ領域への自己書き込み

のインラインアセンブラシーケンスで使ったんだけど

プログラム追ってみたら割り込み許可情報のデータ退避して復帰してる感じだった

無事マイコンの自己プログラミングできた

ありがとう
0389デフォルトの名無しさん
垢版 |
2019/02/24(日) 14:37:48.95ID:YwY0sV++
>>387
+1
変態め
0392デフォルトの名無しさん
垢版 |
2019/02/27(水) 15:03:03.39ID:ZopEvp0k
x86でNASMでELFを組んで学習しているのですが、_startの処理でstack frame設定の処理に質問があります
_startからジャンクデータを残さずEIP,ESPを整えて_exitを呼び出す方法を教えてください
(#立つ鳥後をEAX/EIP以外濁さず、を行いたい理由があります)
_exitはnoreturnで、int 0x80によるsystem_call()、又はSYSENTER(0f 34)によるia32_sysenter_target()
を用いて、SYSCALL_VECTOR又はMSR_IA32_SYSENTER_EIP(0x176)が呼ばれます
通常の_startにおけるlibcの処理では、auxvの中、AT_SYSINFO_HEDR(33)から、vDSO内の
__kernel_syscall_via_epcを経てカーネルへ向かうとの説明です
EXTERN _exit
GLOBAL _start
SECTION .text
_start:
push dword 42
call _exit
をnasm -f elf x.asm; gcc -Wall -s -nostartfiles x.o -o x.outで動きますが、
gccの方でlibgcc.a(-lgcc)やlibc(-lc)が自動で追加されるからなので、
-nostdlibや-nodefaultlibsではSegfaultします。ここの処理の理解のためにcrt0.oを眺めていると,
xor %ebp,%ebp ; stack frameの土台を用意
pop %esi ; [argc][argv][envp][auxv]... で一番上のargcをesiに
...(以下_libc_start_main処理)となり最終的に
sys_exit(int 0x80,eax = 1 (sys_exit),ebx = return code)が呼ばれていました
ソースを眺めると、$grep -r "NR_exit[^_]" /usr/include/
/usr/include/asm/unistd_32.h:#define __NR_exit 1
/usr/src/linux/include/uapi/asm-generic/unistd.h:__SYSCALL(__NR_exit, sys_exit)から
/usr/include/sys/syscall.hから
/usr/src/linux/arch/x86/kernel/entry_32.S:ENTRY(system_call)まで辿り着きましたが、
gdbでスタックを眺めてもいまいち要領が得ません
流れとして、stack->auxv[]->AT_SYSINFO_EHDR->VDSO32_vsyscall->__kernel_vsyscall->CUP依存のコピペ先へ
という理解なのですが…もしかして_start時のスタックの状況に勘違いがあるのでしょうか?
参考にしているのはA Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linuxです
0393L
垢版 |
2019/02/27(水) 16:16:22.81ID:eSoS/w9e
>>392
直感からすると、原因は、esp に一度も値を設定していないことが最も疑わしい。
stdlib などがリンクされている場合、start up コードの中で、esp の値が
設定された後に、main などの自分のコードへと実行が移されるが、
-nostdlib などを付けた場合、リンク時に指定した entry point から
実行が開始される。今の場合、リンク時に entry point を指定していよう
なので、恐らく、最初の object file であるところの x.o の先頭アドレス
であるところの _start かr実行が開始される。

push dword 42 を行ったとき、esp の値が 0 か、または、0x7fffffff などの
値になっているため、segment fault や general protection fault などが
生じると思われる。

ここまでは全て記憶と直感に頼って書いた。
0394デフォルトの名無しさん
垢版 |
2019/02/27(水) 16:18:53.04ID:N0K9USfO
誤: リンク時に entry point を指定していよう
正: リンク時に entry point を指定しないよう


すまないが、あなたの書き込みの全部は読んでおらず、最初の方の
数行を見ての直感で答えた。
0395デフォルトの名無しさん
垢版 |
2019/02/27(水) 16:23:18.32ID:N0K9USfO
>>393
すまん。

esp だけでなく、ss の値も重要。
mov ax,ds
mov ss,ax
などとした方がいいかもしれない。

一番重要なのは、_start: の直後あたりに、

mov esp, (何らかのメモリバッファの底のアドレス)

とする事。メモリバッファは、自分で用意する。
アセンブラ初心者なら、masm なら、db 命令などで領域を静的に
確保し、その最後のアドレスあたりを指定すると良い。

なお、esp を設定するまでは、push, pop, call は行ってはならない。
0396L
垢版 |
2019/02/27(水) 16:37:51.36ID:eSoS/w9e
>>392
「x86」と言っても、OS によって変わってきて、Windows などなら、確か、
ライブラリを全くリンクしない場合でも、最初から esp は、一応、
「使える状態」に設定されていたと(心の中に)記憶している。
つまり、esp は、最初からOSが用意した何らかのメモリ・ブロックの底に
設定された状態で exe の実行が開始されると思う。

組み込みなどでは、esp の値は 0 みたいな値になっているかもしれない。
0397L
垢版 |
2019/03/04(月) 12:10:03.33ID:yv8DGU0u
>>392
gdb が使える状態なら、
・レジスタ ss, esp がちゃんと「正しい」値になっているかチェックする。
・ss == ds なのか、ss = 0 なのか、ss は 0 ではないか、ds とは別の値なのか。
・call _exit の部分の飛び先アドレスがちゃんと正しい相対アドレスになっているか
 確認する。---> 正しくリンクされていない場合もあるため。

_exit 関数が shared library の中にあるような場合、処理系によって call 文がどのような
マシン語になるかは変わってくる場合がある。リンカが、call [addr] 形式の indirect call
を想定する場合と、
call import_func
・・・
import_func:
jmp [_exit_entry]
・・・
_exit_entry dd _exit

などのようになる場合など、さまざま。それが正しくなっているかの確認も必要。
0398デフォルトの名無しさん
垢版 |
2019/07/04(木) 19:46:17.60ID:JhnD4djU
今時のIA32コードを吐く処理系がよく使う命令についてのまとめた資料ってないですかね
486DXあたりでもかなりの命令数になりますが現行で使われている命令は限定されますよね?
0399デフォルトの名無しさん
垢版 |
2019/07/05(金) 11:29:01.09ID:SLYFNUzn
>現行で使われている命令は限定

何言ってんだ
0400デフォルトの名無しさん
垢版 |
2019/07/05(金) 19:14:34.33ID:lm712Ojq
x86系は現行のアーキテクチャとしては間違いなくカオス組。解析器とか作りたくねー
0402デフォルトの名無しさん
垢版 |
2019/10/06(日) 15:58:10.24ID:xhkeezXX
x86 の条件付きジャンプ命令

JG Greater
JL Less
JE Equal
JNE Not Equal
は分かったのですが、
JA
JB
は何の英単語の略なんでしょうか?
0406デフォルトの名無しさん
垢版 |
2019/10/06(日) 17:30:39.06ID:pvG0vkV+
昔は常識だった
0407デフォルトの名無しさん
垢版 |
2019/10/21(月) 09:51:46.99ID:J3DzZudC
アセンブラ買ったらリファレンス一冊ついてたしな...
今ならintelのpdf先に見る所?
0408デフォルトの名無しさん
垢版 |
2019/10/24(木) 10:43:50.55ID:AtkMQyN4
古いのなら日本語マニュアルあるぞ

インテルエクステンデッド・メモリ64テクノロジ・ソフトウェア・デベロッパーズ・ガイド第1巻
インテルRエクステンデッド・メモリ64テクノロジ・ソフトウェア・デベロッパーズ・ガイド第2巻

直リンクはちょくりんNGで貼れないのでググッて
0409デフォルトの名無しさん
垢版 |
2019/10/24(木) 10:52:31.09ID:AtkMQyN4
なんで5chでNGワード扱いされてるんだろうな
全部全角にしてみた

https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/EM64T_VOL1_30083402_i.pdf
https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/EM64T_VOL2_30083502_i.pdf
0410デフォルトの名無しさん
垢版 |
2019/10/24(木) 11:01:40.57ID:ABhN6CSm
EM64T_VOL1_30083402_i.pdf
EM64T_VOL2_30083502_i.pdf

どうみてもこれで充分です
ほんとうにありがとうございました
0412デフォルトの名無しさん
垢版 |
2019/10/25(金) 15:41:34.61ID:4V9sCl2t
>>406
8086のアセンブラと言えば、PC-9801とBASICやMS-DOSの組み合わせだが、
当時パソコンを持っていた人はBASICは知っている人が多く、C言語は
好き物が理解していたが、アセンブラまで理解している人は稀で、
ja の a が above であることを知っている人はごく一部だった。
0413デフォルトの名無しさん
垢版 |
2019/10/25(金) 16:36:39.41ID:BNTJ335Q
>アセンブラまで理解している人は稀

あほすぎ
お前のまわりがそうだっただけだろ
0414デフォルトの名無しさん
垢版 |
2019/10/25(金) 17:38:11.71ID:UlVp4BAq
>>412
当時、The BASICやASCIIでBASICとアセンブラで組んだゲームが山ほど掲載されてた。
同じことをしたいと思ったら8086のアセンブラ知らないとどうしようもなかったんだよ。
BASICはエラー出しても止まってくれたけど、アセンブラでエラー出すとそのままマシンが固まったり
勝手にリブートしたりして何度も泣いたもんだ。けど同時に非常に面白かった。
アセンブラで「どこか1カ所でもミスったらマシンが飛ぶ」と思ったら緊張感がハンパない。
「これで絶対動く」という確信が持てるまで何度も見直してから、震える指でエンターキーを押して
動いたときの感動。立ち上がって全身でガッツポーズしたね。
プログラミングの醍醐味はこれだよ。これ覚えたらもう止められない。
0415デフォルトの名無しさん
垢版 |
2019/10/25(金) 18:16:12.88ID:4V9sCl2t
俺自身はアセンブラは使ってたよ。
しかし、一般的にはそんなに使われている訳ではなかった。
プロのゲームプログラマやそういう雑誌に掲載されたゲーム作者は使っていたが。
そういう人たちは特殊だったので、天才プログラマなんて言葉が生まれた。
0416デフォルトの名無しさん
垢版 |
2019/10/25(金) 18:21:42.17ID:4V9sCl2t
>>414
そういうことを言うと、当時を知らない人はアセンブラなんて誰でもやっていた
などという嘘を信じてしまう。
0417デフォルトの名無しさん
垢版 |
2019/10/25(金) 21:14:38.60ID:UlVp4BAq
>>416
誰でもやってたなんて言ってないんだが。やってた人もけっこういたって程度だろう。
もっと正確に言うなら、当時プログラムをやってた人の総数と、そのうちアセンブラをやってた人が何割いたか
という統計データでも探してこないと正確な割合は出ない。
ただ、そういう本が何冊も出てたってことはそれだけ売れてたってことだから、程度の差はあれ、
アセンブラに興味があった人がそれなりにいたことは間違いない。
0418デフォルトの名無しさん
垢版 |
2019/10/25(金) 23:59:54.86ID:tDdAcA6n
>>417
ja の a が above の意味であることは知っていても、ja が直前の cmp 命令と
組み合わせて使うことや、グラフィックを描くにはG-VRAMと呼ばれる場所に
数値を書くということまでちゃんと理解できた人が少なかった。
0419デフォルトの名無しさん
垢版 |
2019/10/26(土) 02:40:13.17ID:gJ3xyH9v
>>418
PC雑誌、アセンブラのドキュメントと初級解説本、9801の解析本くらい読めば普通に書いてあった。
0420デフォルトの名無しさん
垢版 |
2019/10/26(土) 02:52:45.09ID:dcsgYCXg
>>419
今現在、プログラミングしている人の大部分は、スクリプト言語しか使えない
と言われている。その理由は、ポインタが理解できないから。
ポインタが理解出来ない人は、アセンブラの間接参照 [reg + addr]
も理解できないだろうから、アセンブラではグラフィックもまともに描けない。

当時の常識といっても、今のパソコン使いが当時にタイムスリップしても
大半はアセンブラを理解はおろか使いこなすなど出来ない。
0421デフォルトの名無しさん
垢版 |
2019/10/26(土) 09:59:09.07ID:e6NVGnmw
>>417
>当時プログラムをやってた人の総数と、そのうちアセンブラをやってた人が何割いたか

今より遥かに高い割合で居ただろう
0422デフォルトの名無しさん
垢版 |
2019/10/26(土) 18:30:52.81ID:gJ3xyH9v
>>420
一般の人はアセンブラなんて見たこともないだろうから別にそれはそれでいい。
プログラマーだってアセンブラが使いにくいからC使ってるわけだし。
ただ、アセンブラやっとくとCPUの動作が直にわかるし、簡単なプログラムでも超高速に動く。
Cからアセンブラコードを生成して、内部でどんな処理してるか調べることもできる。
そういうところが面白いと思う人がやればいいんだよ。
0425423
垢版 |
2019/10/27(日) 10:41:06.65ID:MlUkQFx6
>>424
気になりませんよ
ありがとうございます
0426デフォルトの名無しさん
垢版 |
2019/10/27(日) 11:40:07.17ID:CbvQpcn+
試験科目LLVMにすれば良いのに
0427デフォルトの名無しさん
垢版 |
2019/10/27(日) 12:56:27.43ID:duBk5x4n
普通にゲームしかやらんやつの方が多かっただけで
できるやつが少ないかったのは事実
0428デフォルトの名無しさん
垢版 |
2019/10/27(日) 17:04:26.06ID:GpjOYffU
>>427
比率で言えば大体黄金比(2:6:2)になる。昔も今もプログラマーで本当にできるのは上位2割、
全く向いてないのが下の2割、まあまあ普通なのが真ん中の6割。
スクリプトしか書けないのはこの6割の中に入る。上位2割はスクリプトなんてちょっとやればわかるから
何とも思ってない。文字通りレベルが違うから話も合わない。でもそれでいいんだよ。
0429デフォルトの名無しさん
垢版 |
2019/10/27(日) 17:50:07.64ID:9Kmf+J9a
最も利用率が高いのはRubyだが
マイコン相手にすればアセンブラとにらめっこだし
気に入らないが必要とあればC/C++やPythonやJavaScriptも触る
0430デフォルトの名無しさん
垢版 |
2019/10/28(月) 09:34:47.25ID:SaUE9md3
80年代はアセンブラ関連の書籍がたくさんあった
Z80、6809、8086、68000
まだ1989年頃まではCコンパイラが高価だったりして敷居が高かったし
BASICやってた人は高速化するにはマシン語を使ってたしな
アセンブラやマシン語初心者向けのBASICから使えるマシン語の本もたくさん出てた
アセンブラやマシン語を使ってゲームを作る本とかな
電子工作関連でもZ80のアセンブラや周辺LSIのプログラミングで初心者向けの本がたくさんあった
アセンブラ覚えるなら1980年代や1990年代初め頃の方がずっと恵まれてたな
図書館の蔵書とか検索してみるとそういう古い本が出てくるかもよ
0431デフォルトの名無しさん
垢版 |
2019/10/28(月) 09:46:48.07ID:SaUE9md3
今と違って1980年代中ごろまではBASICがメインだったし
ゲームしかやらない人を除けば1980年中ごろまでのパソコンユーザは
プログラミングができるのが当たり前だった
だからパソコンユーザの中でアセンブラもやってた人は多かったよ
そもそもパソコンを扱える人自体が今と違って少なかった
プログラミングに興味がない人はそもそもパソコンにも興味がなかったからな
0432デフォルトの名無しさん
垢版 |
2019/10/28(月) 09:58:42.55ID:SaUE9md3
>>416
当時はパソコンを趣味としてやってる人自体が少なかった
パソコンに興味のない普通の人はキーボードなんて叩いて何が面白いのとかそういう認識
パソコンなんてわけのわからないそんなつまらないものなんでやってるのって感じ
そういう感じなんでパソコンユーザは根暗とかオタクとか言われて馬鹿にされてたからな
0434デフォルトの名無しさん
垢版 |
2019/10/28(月) 10:06:00.01ID:SaUE9md3
マシン語 ゲーム
この2つのキーワードで検索してみると80年代のアセンブラやマシン語の本がたくさん出てくる
0435デフォルトの名無しさん
垢版 |
2019/10/28(月) 15:42:16.95ID:CizzAz3Z
>ゲームしかやらんやつの

ゲームで遊んでた人と
ゲームを造ってた人を
意図的に混同してるだろ

しかもそもそもマ板の話題だし
ム板でするな
0436デフォルトの名無しさん
垢版 |
2019/10/28(月) 15:55:47.51ID:jVNnMdKT
>>431
アセンブラは、本を買ってみたりした人は多かったかもしれないが、
実際に使いこなすまでにいたった人は稀だったはず。
だから、アセンブラやマシン語は難しいという認識だった。

なお、ちょっと話がずれるが、LLVM は、型の部分が煩雑で普通のアセンブラよりも
難しい部分がある。
構造体型を使わなければ普通のアセンブラと同じように出来ないことは
ないが、それでも、bitcast などを頻繁に繰り返す必要がある。
なお、構造体型をヒントに最適化している可能性があるので、面倒でも
構造体型を使う必要があるかもしれない。
上手く整理して理解しないと、コンパイラを作る人泣かせになる。
0439◆QZaw55cn4c
垢版 |
2019/10/28(月) 23:13:33.30ID:dYdO5Ttk
>>430
書籍もそうだが、i486 の時代になっても ms-dos が動き、プロテクトモードは自由に触り放題、というのが当時はすばらしかった
今はプロテクトモードは触らしてもらえない、マシン語化する価値があるものは、キャリーフラグを触れば速くなるもの、くらいしか思いつかない
0440デフォルトの名無しさん
垢版 |
2019/10/29(火) 01:38:16.40ID:axC2qBNh
>>438
当時、Turbo C などが結構使えていた。ところが、リアルモードや
仮想86モードのx86には、640KBの壁ではなく、64KBの壁があった。
それがかなり問題だった。
0441デフォルトの名無しさん
垢版 |
2019/10/29(火) 01:52:33.06ID:axC2qBNh
>>439
>今はプロテクトモードは触らしてもらえない、
最初からOSがプロテクトモードにしてくれている。

MS-DOSで自力でプロテクトモードにするのはかなり大変だったのでずっと
楽になってる。というのは、プロテクトモードにした場合、DOS
は、仮想8086モードで動かさないといけなかった。しかし、そうするためには
非常に膨大なプログラミングが必要になった。仮想8086モードは、設定すれば
すぐ動くわけではなく、割り込みテーブルなどを全部自分で用意しなければ
ならなかったから。割り込みテーブルもテーブルを用意すれば終わりではなく、
ほとんどエミュレータの作成をしてる感じで、32BITプログラムを用意して、
16BITコードでsti,cliやint命令なんかが実行されるたびに、エミュレーション
ハンドらが起動されて、そこでしかるべき処理を行う必要があった。
だから、自力でDOSをプロテクトモードにするのはほとんど不可能で、
DPMIやVCPIという既存のプログラムが利用された。
しかし、それらをまともにつかうのは、TURBO C++などの16ビットコンパイラ
では無理だった。
0442デフォルトの名無しさん
垢版 |
2019/10/29(火) 02:03:23.94ID:axC2qBNh
>>441
DOSで32BITアドレッシングを使うのは、非常に複雑で、80386系CPUの
欠陥か、または、Windowsを売るためにわざとDOSでは32BITアドレッシング
を使いにくくしていたかのどちらかと考えられる。
DOSにおいても、32BITレジスタは簡単に使うことが出来たので、32BITデータ
を読み込んだり32BITで加減乗除を行うのは簡単に出来た。ところが、
アドレスを32BITにすることは原則的にはできなかった。
既に、EMSメモリを使うために、プロテクトモードは使われてしまっており、
DOSは仮想8086モードで動いていた。そのせいで、自作プログラムで勝手に
プロテクトモードをコントロールすることは不可能だった。
というのは、プロテクトモードは、最初にそれを行ったプログラムが
支配者の様になり、他のプログラムは、支配される側としてしか動作できない
仕組みになっていたから。だから、EMSメモリ用の「支配する側のプログラム」
が対応していない限り、支配される側の一般プログラムは、32BITアドレッシング
を使うことは出来なかった。

そのために容易されたのが、VCPIとDPMI。ところが、まともに32BIT
アドレッシングを使うのはVCPIでは難しかったが、DPMIに対応したEMS
ドライバは限られていた。しかも、DPMIを使うにはC/C++コンパイラもそれに
対応していなくてはならなかった。それで、結局、DOSで32BITアドレッシング
を使ったアプリは非常に限られたものとなってしまった。

それが、Windowsが使われた一つの理由、Windowsは、最初から32BITアドレッシング
が使えるようになっていたから。実は、Wintel同盟なるものがあり、恐らく
DOSでは32BITアドレッシングを自由には使えなくするために、80386系CPU
をわざと変な風に設計したのではないかと疑っている。
一般の人は、そんな裏事情を知らない。
0443デフォルトの名無しさん
垢版 |
2019/10/29(火) 07:05:18.63ID:Zl5vhLEl
DOSでは京都マイクロコンピュータが
DOSエクステンダーのEXE386を非商用で実費で配布しててパソコン通信で無料で配布
商用でも1000コピーで100万円くらいで売ってたがそれに対応したコンパイラが高価だったな
海外ではDJCPPがあったが日本ではあまり普及しなかったし、商用ソフトでは使われなかった
唯一の例外はFM-TOWNS
初めからDOSエクステンダーが組み込まれて32bitのDOS環境が使えた
公式のアセンブラが非常に高価でCコンパイラもその高価なアセンブラが必要で
一般ユーザには普及しなかったがFM-TOWNS用にDJCPPが移植された
そのTOWNS用に移植されたDJCPPがEXE386を使うことでPC-98でも使えたが
PC-98ではあまり普及はしなかった

DOSで32bit環境が整ったのがWindows 95が発売される直前
Borland CやWATCOM CなどでCコンパイラにDOSエクステンダーを付けて販売するようになったが
Windows 95が出てみんなもうDOSには興味がなくなっていた

>>442
Windows 3.1まではまだセグメントの64KBの壁があったけどね
Windows 3.1用に32bitのフラットなアドレスが扱えるWin32sが出たね
Win32sはあまり普及はしなかったが
0445デフォルトの名無しさん
垢版 |
2019/10/29(火) 07:24:26.40ID:Zl5vhLEl
アセンブラに話を戻すと
DOSエクステンダーのEXE386はMASMの5.0以上やTurboAssemblerなどのアセンブラで
EXE386上で動作するアプリを作れた
プロテクトモード上の特定のアドレスにVRAMがマッピングされていたので
VRAMへのアクセスも容易だったな

そのEXE386は今でもベクターからダウンロードできる
0446デフォルトの名無しさん
垢版 |
2019/10/29(火) 17:54:53.05ID:VnX4qZP9
>>445
当時、ほとんどのアプリは基本ロジック部分はC/C++言語で書いていて、
グラフィックなどの速度が必要な部分をアセンブラで書くということをやっていた。
だから確かにアセンブラからは32BITアドレッシングは可能であっても、
C/C++が使えなければ現実的に使うことは無理であった。
だから、何らかのC/C++コンパイラが必要となった。それが結構高価であった
ことと、既にWin95に一般民が移行していたので選択の余地は狭かった。
ただし、移行というより、1995はパソコン元年などといわれたくらい、
初めてパソコンを使い始める大挙して押し寄せた。
だから、DOSエクステンダは魅力的ではあっても、その流れに逆らうことは
難しかった。
0447デフォルトの名無しさん
垢版 |
2019/10/29(火) 18:03:50.25ID:I2MyCbhZ
俺の質問めっちゃ低レベル…

LDやSTなどの命令やオペランドは主記憶に記憶されることは分かったんですが、
コメントも同様に、オペランドとかの後に記憶されているんですか?
0450◆QZaw55cn4c
垢版 |
2019/10/29(火) 19:01:39.60ID:Rxtcy1tm
>>441
>プロテクトモードにした場合、DOSは、仮想8086モードで動かさないといけなかった。
いいえ、リアルモードで DOS を起動して、ユーザープログラムが勝手にプロテクトモードに変更してなんら問題ないですよ
プロテクトモードから一時的にリアルモードに戻ることはできませんが、プロテクトモードで割り込みテーブルを再設定すれば問題ないですね

>自力でDOSをプロテクトモードにするのはほとんど不可能で、DPMIやVCPIという既存のプログラムが利用された。
まあそれは事実ですが、あと DOS エクステンダーがよく使われましたね
0451◆QZaw55cn4c
垢版 |
2019/10/29(火) 19:02:55.89ID:Rxtcy1tm
>>442
>既に、EMSメモリを使うために、プロテクトモードは使われてしまっており、
>DOSは仮想8086モードで動いていた。そのせいで、自作プログラムで勝手に
>プロテクトモードをコントロールすることは不可能だった。

EMS なんて非常に使いにくいものはさっさと追放しちゃえばよかったのですよ
0452◆QZaw55cn4c
垢版 |
2019/10/29(火) 19:03:56.60ID:Rxtcy1tm
>>442
>DOSでは32BITアドレッシングを自由には使えなくするために、
66 プレフィックスか 67 プレフィックスで無問題だったかと
0453デフォルトの名無しさん
垢版 |
2019/10/29(火) 19:36:42.19ID:QynZyw6q
まず
80286ではプロテクトモードからリアルモードに戻ることが出来なかったため
戻るために特殊な仕組みが必要になり、プロテクトモードが非常に使いにくかった

386以降は、単純にリアルモードに戻ることが可能になったため使いやすくなり
セグメントのリミットを設定し直してそのまま戻ることで
リアルモード(DOS)から4G全てにアクセスすることも出来るようになった

そして、仮想86モードでの割り込み処理も、別に複雑な処理などは基本的には必要ない
なぜならBIOSにある、元の割り込み処理ルーチンに処理させれば良いだけだから
もちろんIDTをセットアップして処理するプログラムは用意する必要はあるが
大半はスタックにあるリアルモードでの戻り番地等を設定して、
あたかもリアルモードで割り込みが起こったかのようにBIOSやDOSの割り込みベクタテーブルのアドレスに飛ぶだけ

自前で処理する必要があるのは、GPフォルトやページフォルト、
それにA20の操作の処理が入ったらページテーブルを書き換える等するだけ
その程度でも、HMA64KやUMBを用意して空きメモリに余裕があるDOSを動かすくらいなら出来た
(ただし、DMAにも対処するにはまた別途処理が必要)

もちろんEMS等に対応するには、そのための処理ルーチンを用意する必要があるし
EMSやVCPI程度ならともかく、DPMIにも対応するとなると、かなり面倒くさかっただろうとは思う
0454447
垢版 |
2019/10/29(火) 19:46:30.39ID:I2MyCbhZ
>>448
ありがとうございました
ちょっとショックです…
0456デフォルトの名無しさん
垢版 |
2019/10/29(火) 21:13:34.56ID:KWhI3UgV
>>454
コメントは実行に関係ないから削除されて当たり前なんだが、
それがショックという意見は始めて聞いた。なぜ?
0457デフォルトの名無しさん
垢版 |
2019/10/29(火) 21:41:39.59ID:KWhI3UgV
アセンブラでガリガリ書きたい人は、フルアセンブラで書いたOSがある。
プログラムもアセンブラで書く。サンプルプログラムもたくさんある。
DOSのように終わったOSではないので、今のPCにもインストールできる。
Kolibriは初期のMenuetからフォークした32bit OS。Menuetは64bit。
面倒なアドレッシング制限もなく、画面表示も簡単にできる。
日本語にはまだ対応していないので、誰かが日本語化すればユーザが増えるかも。

menuet os
http://www.menuetos.net/

kolibri os
http://kolibrios.org/en/index
0458デフォルトの名無しさん
垢版 |
2019/10/29(火) 21:48:10.11ID:VnX4qZP9
>>452
そのプリフィックスは、データ用とアドレス用のものだけど、
データ用の方はどのモードからも普通に使えた。ところが、
アドレス用の方はプロテクトモードでしか使えず、
仮想8086モードでも使用不可能になっていた。
それが、Wintel同盟がDOSを使えなくしてWindowsだけを使えるように
するための策略だったのではないかと疑っている
(そんな風に設計する理由は特に無かったのに。)。
0459デフォルトの名無しさん
垢版 |
2019/10/29(火) 22:01:50.22ID:VnX4qZP9
>453
>そして、仮想86モードでの割り込み処理も、別に複雑な処理などは基本的には必要ない
>なぜならBIOSにある、元の割り込み処理ルーチンに処理させれば良いだけだから
>もちろんIDTをセットアップして処理するプログラムは用意する必要はあるが
>大半はスタックにあるリアルモードでの戻り番地等を設定して、
>あたかもリアルモードで割り込みが起こったかのようにBIOSやDOSの割り込みベクタテーブルのアドレスに飛ぶだけ

ここは言うほど簡単ではなかった。まず、32BITモードから仮想8086モードの
サブルーチン(割り込みハンドラも)を呼ぶ方法がcall命令としては用意されて
いなかった。だから、32BIT--->V8086モードへは、call命令から帰るリターン命令
の一種であるところのiret命令を使わなくてはいけなかった。その設定が細かい話
になるので細心の注意が必要であった。さらに、V8086--->32BITモードの
呼び出し元へ戻る際には、ret命令ではなく、コールゲートに対する特殊な
call命令か、int命令を用いなくてはならなかった。しかし、もともとのDOSの
割り込みハンドラの最後の部分にはそんな命令が書かれているわけは無いので、
工夫が必要であった。割り込みハンドラから戻ってくるアドレスに、
コールゲートに対するcall命令か、32BITモードに対するint命令かを
「仕掛けて」おく必要があった。どっちにしろ、それはもともと戻るための
命令ではないものを戻る命令として用いているので、スタックなどをきちんと
戻すためには細心の注意が必要だった。
さらに、二重に割り込みが入ったような場合に対応させるためにも、
非常に注意深くスタックの構造を設計しておく必要があった。それは、
32BITモードと16BITモードスタックのの二重構造だった。というのは、
80386のスタックは、32BITモードと16BITモードで全く別の領域を
使う仕組みになっていたので、連続的にすることはできなかったためである。
0460デフォルトの名無しさん
垢版 |
2019/10/29(火) 22:02:17.16ID:VnX4qZP9
>>453
>386以降は、単純にリアルモードに戻ることが可能になったため使いやすくなり
>セグメントのリミットを設定し直してそのまま戻ることで
>リアルモード(DOS)から4G全てにアクセスすることも出来るようになった

ここも、隠れ機能としてそういうものがあると聞いたことがあるが、
多分、ちゃんと公表されていなかったのではないかと思う。
0461デフォルトの名無しさん
垢版 |
2019/10/29(火) 22:38:00.70ID:Zl5vhLEl
>>452
66、67プレフィックスは使えても64KBを超えるオフセットになると一般保護例外が発生する
もう、誰かが書いてるが一度、プロテクトモードに入ってセグメントリミットを設定しなおして
リアルモードに戻れば一般保護例外は発生しなくなるけど、
他のプロテクトモードを使うソフトを一緒に使ってる場合、不具合が発生する可能性はあった
0463デフォルトの名無しさん
垢版 |
2019/10/29(火) 22:46:10.13ID:VnX4qZP9
>>461
Intel公式には、プロテクトモードからリアルモードに戻る方法は無いはず。
確かCPUリセット直後の特殊な状態でごにょごにょすると聞いたような。
0464デフォルトの名無しさん
垢版 |
2019/10/29(火) 22:55:18.61ID:VnX4qZP9
>>463
記憶をたどれば、確か、セグメントリミットを4GBに設定したセグメントエントリ
を持ったGDTテーブルを用意してその先頭アドレスをGDTRに入れた後、
確か、CR0 の BIT をいじった後、far jmpを行うとプロテクトモードに入るが、
far jmpを行わなければ、中途半端な状態になって、4GBアクセスできる
リアルモードになるんだった気がする。だから、その後、far jmpを行うと
モードが切り替わってしまうので、その命令は、アプリが暴走しても
絶対に使っちゃいけない。ただし、リアルモードなのでアプリが暴走すると
OSもつられてこけるので、関係ないっちゃ関係ない。
0465デフォルトの名無しさん
垢版 |
2019/10/29(火) 23:31:54.59ID:Zl5vhLEl
>>463
386はプロテクトモードからリアルモードに戻ることができる
286は戻れないのでハードウェアでCPUだけリセットして復帰するように作る必要がある
PC/ATやその互換機、PC9801の286マシンにはそういう仕組みがハードウェアで備わってる
0466447
垢版 |
2019/10/30(水) 00:23:36.64ID:JIJxpsW5
>>456
機械語からコードを復元する必要があったとして、その時にコメントが
全て消えているとなると、技術者がチクチク解析しないといけないのかな
と思いまして
0468デフォルトの名無しさん
垢版 |
2019/10/30(水) 06:36:17.87ID:hEWImuUH
まず、リアルモードでも仮想86モードでも、
アドレスサイズプリフィックスを使うこと自体ではGPフォルトは発生しない
例えば、lea eax, eax+eax*4 という、5倍する時に使うコードは
仮想86モードでも普通に使える

何度も書いているが、
リアルモードと仮想86モードではセグメントのリミットが64Kに設定されているために
その範囲外にアクセスするとGPフォルトになるというだけなので
一旦セグメントリミットを4Gにしてからリアルモードに戻れば、例外を起こさずに全アドレスにアクセスできる

farジャンプは、パイプラインに残っている命令キューをフラッシュするためのものなので、セグメントリミットとはあまり関係ない

例えば自前で仮想86モードを利用した仮想EMSドライバを書く場合
最初にプロテクトモードに移行してリミットを変え、すぐにリアルモードに戻る
そしてリアルモードのコードで全領域をいろいろセットアップし、それから仮想86モードになってDOSに制御を移すという手法が使えた

仮想86モードでの割り込みハンドラも、仮想86モードでのスタック上にある戻り番地の部分に
割り込みベクタテーブルからの番地を置いて(テーブルにそして保存されているSPも変えて)iretするだけだから
別に難しくない
仮想86中でのiretも何か対処する必要があった気もするけど
いずれにせよGPフォルトのハンドラ内でどんな命令が例外を起こしたか調べる必要があるので、
その内部でiretだったらどうするというテーブルジャンプ対応程度で足りたはず
0469デフォルトの名無しさん
垢版 |
2019/10/30(水) 06:40:30.90ID:hEWImuUH
>>464
リアルモードに戻る正式な手順は、「各セグメントのリミットを64Kに設定してからレジスタ(確かcr0だと思ったが)を設定」で
それを4Gに設定したままで戻れば、64Kの制限が解除される
もちろん16bitレジスタは16bitでしかアドレスできないので、32bitレジスタを使う必要がある
0470デフォルトの名無しさん
垢版 |
2019/10/30(水) 09:06:54.09ID:C/RG5q83
>>468
>farジャンプは、パイプラインに残っている命令キューをフラッシュするためのものなので、セグメントリミットとはあまり関係ない

関係大有りです。リアルモードからプロテクトモードへのモード切替時に、
必ず far jmp命令を行うことが仕様で決まっているのです。
CR0 の PE BITを1にしただけでは切り替わりません。その後に必ずfar jmp
命令を実行するまでがモード切替の手順の一部として決まっています。
0472デフォルトの名無しさん
垢版 |
2019/10/30(水) 15:33:25.51ID:bv6PVv2A
>>457
MonaOS 知ってる人減ったな
0473デフォルトの名無しさん
垢版 |
2019/10/30(水) 23:02:51.33ID:6OkRkWLe
>>466
残念ながらチクチク解析しないといけないです。なぜならもしコメントが残っていたら、「○○製品で使ったコード」とか
社内秘の内容が書いてあるかも知れず、そんなものが外に出たら大変だからです。
ソフトウェアのバージョンとか表に出ても構わない内容ならDBで定数文字列として書いておけばバイナリーにも
残るので逆アセンブルすれば見えます。
0476デフォルトの名無しさん
垢版 |
2019/11/01(金) 06:35:57.29ID:x4OgavLA
Super ASCIIでDOSエクステンダーの連載があったな
その連載の最初の頃にプロテクトモードで64KBのリミッターを解除して
リアルモードに戻るサンプルプログラムが載ってた
DOSエクステンダーの話になってからは雑誌に載るソースコードは一部分のみで
全体のソースコード自体はASCIIがやってたアスキーネットで公開してたけど
0477デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:50:52.10ID:/dldU/F5
昔書いたコードを眺めてみたが
プロテクトモードに移るだけなら far jmp は必要なく、
shortジャンプでキューをクリアするだけで動いてたな

もちろん、16bitプロテクトモードに移るだけでcsのリミットも触っておらず
リアルモードと命令の意味が変わらない(命令長が変化しない等)からこそ出来る技
32bitモードに移行したらプリフィックスの意味も即値やアドレスの長さも全て変わるから
farジャンプは絶対必要だろう

386の時代の話だから、以後のでも通用するかはわからないが
0478デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:51:34.31ID:/dldU/F5
こんな感じ

Enable4G proc
 call Relocation
 add ds:[D_GDTR].@BASE32, eax
 pushr <ds, es>
 pushf
 cli
 lgdt D_GDTR
 mov eax, cr0
 ;and eax, not _PG
 or al, _PE
 mov cr0, eax
 jmp short $+2   ;flush queue
 movseg <ds, es>, GD_D4G, ax
 mov eax, cr0
 and al, not _PE
 mov cr0, eax
 jmp short $+2   ;flush queue
 mov al, 2
 out 0F6h, al   ; A20マスク解除
 sti
 popf
 popr
 ret
 endp
0479デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:53:59.78ID:/dldU/F5
で、仮想86モードに移行する時は、far jmpが必須
なぜなら、仮想86モードに移行するためには
仮想86モード用にセットアップされたTSSを使った特殊なタスクに移行する必要があり
そのためにはプロテクトモード内でのcsの書き換え、つまり、farjmpが必要となるから


これは呼び出し部分

GotoV86  proc
 pushad
 pushr <fs, gs>
 pushf
 
 call ModeSwitch
 
 popf
 mov al, 3
 out 0F6h, al   ; force A20 OFF
 popr
 popad
 ret
 endp
0480デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:54:59.94ID:/dldU/F5
ModeSwitch proc
; call Enable4G
 call SetAddress
 call SetupIDT
 call SetupTSS
 
 xor eax, eax
 mov es, ax
 call CleanEMB   ; これ以降、es=0
 call SetupPageTable
 call MoveCode
 call Setup8259A
 
 prefixd32  ;32bit gdtr (not 24bit gdtr)
 lgdt GDTR
 prefixd32  ;32bit idtr (not 24bit idtr)
 lidt IDTR
 
 mov eax, cr0
 or eax, _PG + _PE  ; 直接ページングをON
 mov cr0, eax
 jmp short $+2  ; flush queue
 mov ax, GD_D_TSS  ; タスクレジスタにダミーの設定
 ltr ax
 
 call VGtest
 FLUSH GD_V_TSS ; jmp far seg, $next
 ret
 endp


最後に far jmpしてる
0481デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:56:48.06ID:x4OgavLA
Super ASCIIに載ってたサンプルコード
https://pastebin.com/0Tk0U9Y1
(TASMで動作確認済み)

PC9801用のテストプログラム(VRAMを80808080で埋めてるだけです)
.386p
assume cs:prog,ds:prog
prog segment use16
org 100h
mov ah,40h
int 18h
mov ah,42h
mov ch,0c0h
int 18h

mov eax,0
mov es,ax
mov edi,0a8000h
mov ecx, 32768*3/4
mov eax, 80808080h
cld
db 67h
; use ecx for loop counter
rep stosd

mov ax,4c00h
int 21h
prog ends
end
0482デフォルトの名無しさん
垢版 |
2019/11/01(金) 08:58:53.01ID:x4OgavLA
サンプルコード、テストプログラムともにCOM形式なので
LINKした後にexe2bin protect.exe protect.comとcom形式に変換する必要があります
0483デフォルトの名無しさん
垢版 |
2019/11/01(金) 11:55:34.87ID:iX6unUP8
知らない人が多いようなので書いておくと、
実測してみると pusha より、ばらばらの push 命令を書いたほうが速度が速い。
一つの理由は、push espという無駄なpushが1つ減らせるから。
これはQEMUなどを使っているだけでは分からない事実。

なお、こっちは良く知られたことだけど、enter, leave 命令より、
push ebp, mov ebp,esp, sub esp, nn などと書くほうが速い。

もっと言えば、486だとなぜかinc, dec が2クロック掛かってしまうのに、
add esp,1 や sub esp,1 は1クロックで済むという事実を知る人は少ないらしい。
0484デフォルトの名無しさん
垢版 |
2019/11/01(金) 11:58:53.09ID:iX6unUP8
>>483
補足。QEMU だと、pusha が1命令分の時間で済むのに対し、バラバラの
push命令に直してしまうと、その個数倍の時間が掛かるので、8倍程度後者
の方が遅い。実機だと、後者の方が16%程度速い。実機とQEMUでは全然
速度バランスが違うので、QEMUでの速度測定は全く参考にならないので注意。
0485デフォルトの名無しさん
垢版 |
2019/11/01(金) 12:10:32.63ID:iX6unUP8
>>477
正確には short jmp だったか、far jump だったかは資料を見てみないと
思い出せないけど、少なくとも Wikibooksには、
6. Set the PE bit (and the PG bit if paging is going to be enabled) of the
 MSW or CR0 register
7. Execute a far jump (in case of switching to long mode, even if the destination
 code segment is a 64-bit code segment, the offset must not exceed 32-bit
 since the far jump instruction is executed in compatibility mode)

また、https://stackoverflow.com/questions/26679682/how-does-setting-the-pe-flag-in-cr0-enable-protected-mode
にも、
1. Set up a global descriptor table (gdt) and load it using the lgdt instruction
2. Set the PE flag/bit in the control register CR0 to enabled (ie. to the value 1)
3. Execute a long jump with ljmp

Technically the CPU internally stores the selector information of all selectors used.
Whenever a selector register changes then the limit, base and so on are loaded.
This means that loading the CS register is required for updating the base, limit
and so of the CS register. This means: A far jump must be done (because this
will load the CS register). Maybe a RETF would also work...

I'm not sure if loading the other segment registers (for example DS) would
already work before the far jump so if you load the DS register before the
far jump the base address and limit will be taken from the GDT. Would be
nice to try this out...

と書かれている。
0486デフォルトの名無しさん
垢版 |
2019/11/01(金) 12:19:54.06ID:iX6unUP8
>>485
だんだん思い出してきたので書いておくと、GDTRにGDTのアドレスをセットした
だけでは、CPU内部のセグメントレジスタの情報が更新されない。
例えば、dsには、リミット、ベースアドレスなどの情報がCPU内部に入っているが、
GDTRを更新した段階では、CPU内部のそれらの情報は更新されない。
更新されるのは、mov ds,ax や、pop ds, lds などを実行した場合のみ。
つまり、mov ds,ax などを実行して始めて、CPU内部のdsレジスタに関する隠れ
情報格納場所の情報までが更新され、dsにプロテクトモードらしいセグメントが
対応するようになる。

一方、csレジスタについては、mov cs,ax などの命令が無いので、その代わりになる
のが、far jmp ということになる。far ret や iret などでもいけるかもしれないが、
仕様上は far jmp ということになっているのだと思う。だから、プロテクトモードに
初めて突入したい場合に、far jmp 以外の命令でcs を更新した場合にどうなるかは
保証されていないかもしれない。
0487デフォルトの名無しさん
垢版 |
2019/11/02(土) 18:02:51.42ID:cEPd2nC/
低レベルな相談です

ADDL・ADDA・SUBL・SUBA・AND・OR・XOR・CPL・CPA命令において
オペランドの第2引数に、=を付けるのをつい忘れてしまうんですが、
何か対処法はありますか?
0488デフォルトの名無しさん
垢版 |
2019/11/02(土) 22:19:49.20ID:dJ3V2vrm
>>487
CASL II は始めて見たんだけど、
http://masudahp.web.fc2.com/casl2/casl2110.html
http://masudahp.web.fc2.com/casl2/casl2120.html

ADDA GR0, =#0045
のように書くと、自動的にラベルを生成して、
ADDA GR0, DATA1
・・・
DATA1 DC #0045
と書いたの等価になるらしいから、忘れるとか言う問題ではなく、
CASL II言語の基礎なので自然に覚えるしかないですね。
アセンブリプログラミングには、このくらいの記憶力は必要です。
ただ、丸覚えするのではなく、ちゃんと理解すれば自然に覚えられると思います。
0489デフォルトの名無しさん
垢版 |
2019/11/02(土) 22:41:38.43ID:dJ3V2vrm
>>488
実際のCASL IIがそう書けるかどうかはともかくとして、
数学記号と同様の感覚で記号の対応関係や「類推(推論)」で考えれば、
ADDA GR0,#0045
と書くと、アドレス #0045 番地のメモリーに入っている内容を読み出した値を
GR0に足す、という意味になります。# は以後の数値が16進数である事を表す
記号です。初めに言ったようにこの書き方がCASL II 言語で実際に出来るか
どうかは分かりませんが、意味で考えるとそういう意味になるでしょう。一方、
ADDA GR0,=#0045
は、>>488 に書いたように、0045 という16進数の値を入れた領域を
自動的に確保して、そのアドレスを xxx とすると、自動的にその場所を
ADDA GR0,xxx
という命令に置き換えるという意味です。
かなり違う意味です。ですから、覚える覚えないの話では無い事が分かります。
0490デフォルトの名無しさん
垢版 |
2019/11/02(土) 22:47:11.43ID:dJ3V2vrm
>>489
x86アセンブラを知っている人ならば、
ADDA GR0,GR1    --->  mov GR0,dword ptr [GR1]
ADDA GR0,#0045   --->  mov GR0,dword ptr [0045h]
ADDA GR0,=#0045  --->   mov GR0,0045h
また、C言語を知っている人ならば、
ADDA GR0,GR1   --->  GR0 += *(DWORD *)GR1;
ADDA GR0,#0045  --->  GR0 += *(DWORD *)0x0045;
ADDA GR0,=#0045 --->   GR0 += 0x0045;
となります。

対応関係は、第二オペランドに X を書くと、[X] や、*X の意味になり、
=X と書くと、X の意味になります。
0491デフォルトの名無しさん
垢版 |
2019/11/02(土) 22:48:31.37ID:dJ3V2vrm
>>490
すみません、movとaddを書き間違えました。正しくはこうです。:
x86アセンブラを知っている人ならば、
ADDA GR0,GR1    --->  add GR0,dword ptr [GR1]
ADDA GR0,#0045   --->  add GR0,dword ptr [0045h]
ADDA GR0,=#0045  --->   add GR0,0045h
0492487
垢版 |
2019/11/03(日) 00:10:58.78ID:7OJOBan9
>>488-491
ありがとうございます
学習していきたいと思います
0493デフォルトの名無しさん
垢版 |
2019/11/12(火) 18:31:03.25ID:m5a+lCw/
マイコン用のアセンブラコードジェネレータを作りたいんだけどどんな感じにするのが良いんだろうか
if文で条件分岐させていくとコード生成部が条件分岐だらけになって訳が判らなくなる
組み込み用なのでパイプラインのストールを引き起こすようなコードはなるべく生成したくない
0494デフォルトの名無しさん
垢版 |
2019/11/12(火) 18:53:07.41ID:I0vQskxn
bison+flex+LLVM
0497493
垢版 |
2019/11/13(水) 08:08:30.10ID:HNnV6bHC
ありがとう

>>494
判りにくくてスマン。ガチの処理系を作りたいわけではないんだ
チップメーカーが出しているGUIでパラメータをポチポチ設定してGeneratボタンをクリックすると
設定に従ったライブラリコードを自動生成してくれるみたいな奴を作りたい
というかLLVMとかは自分の手におえそうにない

>>495
ハッシュテーブルみたいな感じ?パターンは結構ある
今考えているパラメータだけでも
書き込み先アドレスが〜30種程度と〜10種類程度×2
処理の選択にbool値が5個くらい、サイクル数指定が3種
サイクル数を指定できる区間は重なっているし結構ややこしい
ちょっと前から作り始めているけどすでにぐちゃぐちゃ・・・
0503デフォルトの名無しさん
垢版 |
2019/11/21(木) 05:15:38.34ID:1McLuuYz
すでに何かのアセンブラ理解してるなら両方勉強しても数日で理解できるだろう。
はじめてアセンブラ勉強するならそりゃシンプルな8bitCPUで圧倒的に情報が多いZ80だろうな。
0504498
垢版 |
2019/11/22(金) 00:24:30.25ID:I5J2JfnT
返信が遅くなってすいません
答えて頂いた方、ありがとうございました
0505デフォルトの名無しさん
垢版 |
2019/11/22(金) 13:34:09.59ID:zKQgPoBc
マジレスするとアセンブラを使う目的次第

PICやRL78みたいな小規模でCPUや電子回路を学ぶ
x64で高速化やSIMDを試す
ラズベリーパイやスマホのARMで遊んでみる
DSPで信号処理やフィードバック制御を学ぶ

など
0506デフォルトの名無しさん
垢版 |
2019/11/22(金) 15:29:17.71ID:gUUFthXr
>>498
6809
0507デフォルトの名無しさん
垢版 |
2019/11/22(金) 16:26:18.45ID:2jFqraTL
>>498
ニモニックの美しさと分かり易さではZ80。
実用的には8086。
0508デフォルトの名無しさん
垢版 |
2019/11/22(金) 16:34:56.93ID:2jFqraTL
>>507
ちなみに、CPUとしては両者は親戚みたいなもので、Z80を学んだ後から、
8086へ進んでも文化に共通点が多いので理解し易い。
たとえば、条件分岐は、cmpなどの比較命令を実行して
zero flag や carry flag などに影響を与えた後に、Jcc 命令を使う点や、
cmp以外にsubやaddでも全く同様に zero flag, carry flag などに影響を
与えると言う点が両者で共通している。
他のCPUでは全く違うやり方をとるものも多い。

ところが、Z80は8BIT CPU としてはとても上手くできていた方だが、
8086は、16BIT CPU としては残念な方であった。一つの理由は、
当時は低価格で理想的な16BIT CPUを作るためには、ICにおけるトランジスタの
集積度が不足していたが、8BIT CPUを作るには十分であったためらしい。
なので、8BIT CPUは使い易いものが作れたが、16BIT CPU は使いにくいもの
しか作れなかった、と考えることが出来る。
0509デフォルトの名無しさん
垢版 |
2019/11/22(金) 16:45:49.82ID:gUUFthXr
80186 で恥の上塗りですね判ります
0510デフォルトの名無しさん
垢版 |
2019/11/22(金) 16:56:01.19ID:2jFqraTL
>>508
他にも、

1. 両者とも、アラインの揃ってないアドレスからでも16BIT以上のデータを
 読み出せると言う特徴がある。これが出来ないCPUも多く、Apple系は昔そういう
 CPUを使っていたと聞いている。今でもC言語の構造体などで align が細々と
 決まっているのは、後者の文化圏の人達が主導しているのかも知れない。

2. carry flag(8086 では「borrow flag」という名前になっている)を使うと、
 多倍長の加減算が容易に出来るのも両社に共通している。この特徴は、
 他のCPUには無いことが多いらしい。だから、LLVMなどには adc や sbc(sbb)
 相当の命令が無いし、carry flag を捕捉する命令も定義されていない。

3. LLVM では、単純な引き算の延長線上にある cmp 命令でフラグを作った後、
 条件の種類によっていろいろな種類のJcc で条件分岐するという流儀をとっておらず、
 条件の種類によって比較命令自体を変えてしまって、結果は常に 1BIT の
 BOOL値とし。逆に Jcc 命令は原則一種類となっている。これは、LLVMが
 Z80や8086とは異なる文化圏の人が作ったものであるのではないかと推定される。

4.アカデミカルな世界では、CPUとして、業界事実標準の Z80 や 8086 系統ではなく、
 どうも違う文化のものを想定していることが多い気がする。
 色々な言葉が、Z80 や 8086 ではかなり多く共通しているが、LLVMとは全く
 違う。
0511デフォルトの名無しさん
垢版 |
2019/11/22(金) 17:05:38.22ID:zKQgPoBc
まあ普通にx64かARMかMIPS

ARMやMIPSはもともとRISCなので非常にきれいでシンプル

x64はAVXなどのリッチな命令を楽しめるし
環境もPCにVisual Studioを入れるだけ
0512デフォルトの名無しさん
垢版 |
2019/11/22(金) 17:09:00.41ID:zKQgPoBc
80186(改)は実はわりと最近まで製品で使ってましたよ
大きなLSIの中に、制御用にコアだけ入ってるやつ
セグメントレジスタが4シフトではなく8シフト
0513デフォルトの名無しさん
垢版 |
2019/11/22(金) 17:10:09.89ID:omZwaM5I
>>510
シッタカで出鱈目書くなよ糞が
0516デフォルトの名無しさん
垢版 |
2019/11/22(金) 17:54:18.76ID:UNbCtceI
>>513
知ってる人は自分が正しいと思うことを具体的に書けばいい。
書けないなら黙っとけと思う。
0517デフォルトの名無しさん
垢版 |
2019/11/22(金) 18:28:01.42ID:hDmJhEnO
>>510じゃないけど

1.性能上(もしくはアトミック性)の理由でアラインメントを揃える

2.8086でもキャリーフラグという名前
もちろんボローの意味でも使う

フラグはOut Of Orderの妨げになりやすく
シンプルな設計を目指したRISC系では使わないし
当然SIMDでも使わない
ただし、命令を組み合わせて同じことが出来る

多倍長の加減算は(乗算他に比べて)速いので
それが性能に影響することは少ないし
64bit CPUではそもそも64bitを越えた演算をすることも非常に少ない
0519デフォルトの名無しさん
垢版 |
2019/11/22(金) 18:33:09.28ID:hDmJhEnO
4.z80はまったく業界標準ではないですね
数量から言えばARMとx86系が圧倒的

MIPSは教育現場では使われるけど
数量はARMやx86系に比べたら少ない

x86も16bit命令で組む事はほぼない
32bitか64bitがほとんど
0522デフォルトの名無しさん
垢版 |
2019/11/22(金) 18:43:24.01ID:LRWcxGhp
いまどき初心者がZ80に興味持つはずないだろ
こいつが御高説を垂れたいがために質問を自演してるんだろ
情けない奴
0523デフォルトの名無しさん
垢版 |
2019/11/22(金) 19:07:15.94ID:sA8M4Dff
Z80そのものが使われる機会は減っていてもZ80の流れを汲むアーキテクチャはまだまだある
IA32/AMD64はもちろん、ちょっと上であがっているRL78もだ
0525デフォルトの名無しさん
垢版 |
2019/11/22(金) 19:26:38.06ID:sA8M4Dff
組み込み系でも8bitだと桁上がり演算でキャリーをよく使うけど32bitだと出番は激減する
32bitあれば12bitADCの変換値を10回足し込むくらいじゃ余裕
一部のアーキテクチャは特殊演算用に64bitを超えるレジスタを持っていたりするし
なおさら桁あふれしにくい
0527デフォルトの名無しさん
垢版 |
2019/11/22(金) 21:52:14.02ID:DXtwsE0I
Intel系のCPUは元々4bitの4004から来ている。4004は主に電卓で使われた。4bitレジスタで演算するとき
桁あふれが頻繁に起こるのがわかっていたのでキャリーフラグがあると便利だろうということで入れたんだと思う。
それが8bitの8008以降も継承されて現在に至る。だから64bitでキャリーフラグが使われないのも当然。
0529デフォルトの名無しさん
垢版 |
2019/11/22(金) 22:22:56.50ID:2jFqraTL
>>517
>ただし、命令を組み合わせて同じことが出来る
一年ほど前に調べていたら、x+y に対するキャリーフラグをC言語を使って
作り出すようなことを書いているコードを見つけた。
普通に考えればx,yの最上位ビットに着目すればいいんだけど、
最初に思いつくコードよりかなり短いコードだった。
x,yが8BITの場合、x+yに対するキャリーフラグをcfとすると、
意味的には、
cf = 0;
if ( (x & 0x80) != 0 && (y & 0x80) != 0 ) {
 cf = 1;
}
でいいはずだけど、
cf = (x & y) >> 7;
かな。でも、もっとエレガントなコードだったような気がする。
何か知っていれば教えて欲しい。
0530デフォルトの名無しさん
垢版 |
2019/11/22(金) 22:28:55.69ID:2jFqraTL
さらに、x, y が符号なし8BIT整数の場合の x - y に対する carry flag については、
cf = 0;
if ( x < y ) cf = 1;
で一応求まるんだと思う。
また、sf(sign flag) に関しては、
sf = 演算結果 >> 7;
でいいと思われる。
0537デフォルトの名無しさん
垢版 |
2019/11/23(土) 03:01:11.70ID:eMnkZzKn
carry = 0;
for (i=0 ; i < n ; i++){
. . if (carry){
. . . . z[i] = x[i] + y[i];
. . . . carry = z[i] < x[i];
. . }
. . else {
. . . . z[i] = x[i] + y[i] + 1;
. . . . carry = z[i] <= x[i];
. . }
}
0538デフォルトの名無しさん
垢版 |
2019/11/23(土) 03:03:32.41ID:eMnkZzKn
borrow = 0;
for (i=0 ; i < n ; i++){
. . if (carry){
. . . . z[i] = x[i] - y[i];
. . . . borrow = z[i] > x[i];
. . }
. . else {
. . . . z[i] = x[i] - y[i] - 1;
. . . . borrow = z[i] >= x[i];
. . }
}
0539529
垢版 |
2019/11/23(土) 11:50:40.96ID:U8iKLMmJ
自己訂正です。
実は、色々と間違いがあり、次のようになっています:
>>529 : 間違い。
530 : 正しい。
531 : 正しい。
>>532 の前半 : 正しい。
>>532 の後半 : 間違い。

改めて、>>529 の根本的な間違いとして、carry flag は、演算前の最上位ビットだけでは決まる、
というのが大間違いでした。下位ビットからの桁上がりがあるためです。

まとめると、x, y が符号なし整数の場合、

1. a = x - y に対する carry flag :
  cf = (x < y);
  または。
  cf = (a > x);

2. a = x + y に対する carry flag :
  cf = (x < (-y));
  または。
  cf = (a < x);

です。上記の「または」以後のやり方は、>>536 537 538 で思い出させていただきました。
一年ほど前に見たやり方がそれだったと思います。とてもエレガントですね。
0540デフォルトの名無しさん
垢版 |
2019/11/25(月) 14:32:25.64ID:1+9AnSdf
MIPS64やRISC-VのRV64Iで128bit加算減算のアセンブラ出力してみると
おなじようなことやってるね

mips64 128bit加算 $4:$2 ← $5:$4 + $7:$6
    daddu    $2,$4,$6
    sltu     $8,$2,$4
    dext     $8,$8,0,32
    daddu    $3,$5,$7
    daddu    $4,$8,$3

mips64 128bit減算 $4:$2 ← $5:$4 - $7:$6
    dsubu    $2,$4,$6
    sltu     $8,$4,$2
    dext     $8,$8,0,32
    dsubu    $3,$5,$7
    dsubu    $4,$3,$8

risc-v RV64I 128bit加算 a6:a7 ← a1:a0 + a3:a2
    add     a7,a0,a2
    sltu    a6,a7,a0
    add     t1,a1,a3
    add     a6,a6,t1

risc-v RV64I 128bit減算 a1:a2 ← a1:a0 - a3:a2
    sub     a2,a0,a2
    sgtu    a0,a2,a0
    sub     a1,a1,a3
    sub     a1,a1,a0
0542デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:12:36.09ID:xy0IaHJE
>>525
何かいろいろ勘違いしてるようだが、キャリーフラグは条件ジャンプのときにも参照するんだぞ。
MIPSが欠陥品だと言われる理由がこれで分かるだろう。
0543デフォルトの名無しさん
垢版 |
2019/11/28(木) 08:14:06.75ID:xy0IaHJE
MIPS以降の多くのRISCベースのCPUはすべてキャリーフラグがある。
とても効率的で不可欠だからだ。
0545デフォルトの名無しさん
垢版 |
2019/11/28(木) 19:56:47.34ID:PoPpbfsh
フラグはアウトオブオーダーの妨げになるし
並列化も出来ないから
高速化に対してはイマイチ
0550デフォルトの名無しさん
垢版 |
2019/11/28(木) 21:56:14.84ID:aqT8+si8
jbという条件ジャンプ命令は使っているけど
jcという条件ジャンプ命令は使っていないので、キャリーフラグを使うことはない

アホくさ
0551デフォルトの名無しさん
垢版 |
2019/11/28(木) 23:10:51.33ID:xy0IaHJE
>>545
そういう嘘を真に受けてはいけない。
実際のCPU見れば並列実行能力の高い処理系はすべてキャリーフラグ持ってるし、
むしろ並列実行能力がとくに低いMIPSはキャリーフラグ持ってない。
0552デフォルトの名無しさん
垢版 |
2019/11/29(金) 01:09:48.76ID:IDh/GqUP
条件分岐でキャリーフラグの使い方が分からない、使ったことがない、使われることを知らなかった、という人はなんだろう。
6502、Z80、6809、AVR、8086、68K、ARMとメジャーなCPUどれから始めてもマニュアル、入門書には書いてると思う。
0554デフォルトの名無しさん
垢版 |
2019/11/29(金) 15:12:01.44ID:YkvT9y9m
>>551

x86なんかキャリーフラグじゃない別のフラグを使った加算とか
歪んだ方向に行ってる

SIMDによる並列化プログラムも
フラグは単なるループ条件くらいにしか使わん
maskレジスタがその役目を継ぐ
0556デフォルトの名無しさん
垢版 |
2019/11/29(金) 18:54:08.05ID:9qxidx0X
キャリーフラグを持たないアーキテクチャ・・・
MIPS?PPC?IA-64?死屍累々じゃねーかw
0557デフォルトの名無しさん
垢版 |
2019/11/29(金) 19:13:07.84ID:K9qn0Fk+
>>545
>フラグはアウトオブオーダーの妨げになるし
>並列化も出来ないから
また嘘書いてやがる
Core iプロセッサはフラグがあってもアウトオブオーダーしまくりですが?
アウトオブオーダーを正しく理解してたら絶対にこんなことは書かない
分岐も、投機実行で大凡はカバーされるということになっている

フラグの問題は、元の機械語の並べ方に制約が生じるだけで、アウトオブオーダー実行には関係ない
アウトオブオーダーを妨げるケースでも、元のCISCの挙動に合わせるためで、アウトオブオーダーが
関係しているのではない

>SIMDによる並列化プログラムも
>フラグは単なるループ条件くらいにしか使わん
>maskレジスタがその役目を継ぐ
これもまともに理解してないからこそ書ける内容だな
Pen Proになってアウトオブオーダーが使えるようになった時にcmovが導入されたし、
「単なるループ条件」でも投機実行が必要なんだが?

ここまで酷いとお前に語る資格はないよ
0558デフォルトの名無しさん
垢版 |
2019/11/29(金) 19:39:22.16ID:4DEcYZGM
アウトオブオーダーの妨げの意味がわからんのだね
なんでx86に変な命令があるのか考えてみ
0559デフォルトの名無しさん
垢版 |
2019/11/29(金) 19:42:57.97ID:4DEcYZGM
フラグは本来依存性の無い処理まで依存性が出てくる
フラグが共通だから

レジスタのようにフラグが複数セットあって指定出来ないとダメ
そらがmaskレジスタであったりx86の変な命令であったり
0560デフォルトの名無しさん
垢版 |
2019/11/29(金) 20:21:52.83ID:K9qn0Fk+
>>548,549
ID:YkvT9y9mがID変えたのか、別人なのかどっちだ?

アウトオブオーダーってのは、真の依存関係にない部分を抽出して同時に実行するっていう
アーキテクチャーだ
ループの2周目以降は前の分岐に依存しているから、本来は順番にしか実行できない
しかし、分岐は数値演算と違って結果のパターンが極めて限定されているので、
決め打ちで一時的に依存関係を無視して処理を進めるのが投機実行だ
アウトオブオーダー実行にはフラグレジスタの存在など関係なく、結果に依存関係が
あるかどうかが問題なんだよ
そんなことも理解せずに語ってたのかって言ってんだよ
0561デフォルトの名無しさん
垢版 |
2019/11/29(金) 20:34:10.69ID:4DEcYZGM
フラグを使う演算だと依存関係が出るって言ってんの

関係ない演算でもフラグのせいで依存関係が出る
同じフラグを使うから
0563デフォルトの名無しさん
垢版 |
2019/11/29(金) 20:58:00.49ID:K9qn0Fk+
jaもjbもキャリーやゼロや符号の論理演算で表現されるのに、どうしてキャリーフラグが
どうのって話になってんの?

>>561
お前がアウトオブオーダーを理解できてないのはわかった

>フラグを使う演算だと依存関係が出るって言ってんの
>関係ない演算でもフラグのせいで依存関係が出る
>同じフラグを使うから
やはり論理レジスタと物理レジスタの理解も出来てないな
フラグを格納できるレジスタが複数あろうがなかろうが、それは命令アーキテクチャの問題であって
アウトオブオーダーの問題ではない
これでどうしてアウトオブオーダーの妨げになるんだよ?

>x86の変なフラグを使う歪んだ命令は何のため?
その変な命令って何だよ?
0565デフォルトの名無しさん
垢版 |
2019/11/29(金) 21:30:22.27ID:Mi7N2zYE
>>552
なんか勘違いしてる。CYの使い方がわからないのではなく、使う場面が少ないからあまり意識しないんじゃないかということ。
0566デフォルトの名無しさん
垢版 |
2019/11/29(金) 21:44:01.72ID:IDh/GqUP
>>564
mips64
daddu    $2,$4,$6 1clock目
sltu     $8,$2,$4 1clock目
dext     $8,$8,0,32 2clock目
daddu    $3,$5,$7 1clock目
daddu    $4,$8,$3 3clock目
3clock 演算回数 計5回 (加算3回、減算1回、シフト1回)

risc-v
add     a7,a0,a2 1clock目
sltu    a6,a7,a0 1clock目
add     t1,a1,a3 1clock目
add     a6,a6,t1 2clock目
2clock 演算回数 4回 (加算3回、減算1回)

amd64
add 1clock目
adc 2clock目
2clock 演算回数 2回(加算2回)

mips、risc-vは必死に並列化してるのに速くならない。
むしろキャリーがあったほうが無駄な演算回数が減り消費電力も減り、
演算器に空きができ、他の計算の余力を得ることになり、並列処理能力は上がることが分かる。

キミのいう依存関係が出てmipsのほうが速い例を挙げてほしい。
0568デフォルトの名無しさん
垢版 |
2019/11/30(土) 07:32:32.63ID:zk5zlAHc
>>556
最近巷をさわがせてるRISC-Vもキャリーフラグはないぞ
今あるCPUの中で最も新しいアーキテクチャなんだが
0569デフォルトの名無しさん
垢版 |
2019/11/30(土) 07:35:49.37ID:zk5zlAHc
MIPSの話が出るとすぐにキャリーフラグを連呼する例の人かな
彼は8bitCPUの話が好きみたいだが
もう、既に死んでる6502、Z80、6809、68Kあたりを挙げてるからすぐにわかる
0571デフォルトの名無しさん
垢版 |
2019/11/30(土) 07:45:40.61ID:xhEM6aVw
>>568
> 関係ない演算でもフラグのせいで依存関係が出る

RISC-V信者さんって大学の人でしょ? 例を出してよ。どんな演算?
0574デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:05:52.96ID:xhEM6aVw
>>573
> フラグはアウトオブオーダーの妨げになるし並列化も出来ないから

> 変なフラグを使う歪んだ命令は何のため?

逃げてばかりいないでどういうことか説明してくれよ。コード例がひとつも出ないってどういうことだよ。
128bit加算ではMIPSのほうが遅くなってるし。これ依存関係のない128bit加算が複数あったら
パイプラインが先に詰まるのは演算回数の多い、MIPS、RISC-Vじゃん。>>566
0575デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:10:23.93ID:zk5zlAHc
RISC-Vの中国製チップを使ったマイコンボード手に入れたが、
普通にCortex-A7クラスのIPCがあってびっくりした

ARMと違ってRISC-Vなのでおそらく中国の半導体メーカーがコアの設計までしたんだろうな
RISC-Vならオープンソースのコアがあるから
中国の半導体メーカーでもそれを参考にして設計できるんだろうね

RISC-Vは中国やインドで推進してるから今後普及していくだろうね
0576デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:12:36.49ID:WebQyLi7
SIMD命令にキャリーフラグやADC/SBB/RCR/RCL命令が無いのが
演算としては使わないっていう証拠
こういった命令は昔のチープな環境のなごり
0577デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:14:24.92ID:zk5zlAHc
>>574
たとえば、

CMP EAX,10
JB hogehoge

こんなコードだと比較命令でフラグレジスタが変わるが
次の命令ですぐにフラグレジスタを参照してるってことじゃないの?
俺が発言したわけじゃないから知らんけど
0578デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:25:28.29ID:xhEM6aVw
>>577
mips、risc-vも依存して並列実行できない例を出されてもだな。
しかも投機実行されるintelx64のほうがさらに速くて、mips、risc-vはストールする例だし。
0579デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:30:24.01ID:zk5zlAHc
>>578
x86だと演算命令で必ずフラグの値が変わるので
比較命令とジャンプ命令の間にフラグの値が変わるようなほかの命令を挟めないからね
0580デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:33:19.07ID:zk5zlAHc
そもそもキャリーフラグが有用なのは2進バイナリの多倍長演算の時だけ
64bitCPUではほぼ出番がない
0581デフォルトの名無しさん
垢版 |
2019/11/30(土) 08:45:13.32ID:xhEM6aVw
挟むめないって挟む理由あるアルゴリズムなんて存在するか?
そんなコード書ける高級言語はないし。キミは一体RISCで何を計算したいんだ?
0582デフォルトの名無しさん
垢版 |
2019/11/30(土) 09:00:24.68ID:zk5zlAHc
アセンブラの話してるのになんで高級言語の話になるのかな?
MIPSならslt $2, $3, 11とジャンプ命令の間にほかの命令を挟めるってこと
0583デフォルトの名無しさん
垢版 |
2019/11/30(土) 09:22:02.63ID:xhEM6aVw
>>582
そうではない。挟まなきゃならない理由を聞いている。
それで並列化できなかったものが並列化可能なら例になるがそうではない。判定の前に命令書いても依存関係がなければ並列化される。
キミの例は可読性が悪くなる書き方ができるというだけで並列化できる例ではない。むしろMPSの欠点だ。

> フラグはアウトオブオーダーの妨げになるし並列化も出来ないから

の例を聞いてるんだよ。ひとつも例が出せてないじゃないか。
0584デフォルトの名無しさん
垢版 |
2019/11/30(土) 09:40:23.31ID:zk5zlAHc
演算のたびにフラグレジスタが変化するのは無駄だとは思うけどね
特にアドレス計算のたびにフラグレジスタが変化するのはうっとうしい
ARMだと加算減算命令はフラグレジスタが変化するものと変化しないのと2種類用意されてるね
0585デフォルトの名無しさん
垢版 |
2019/11/30(土) 09:43:31.34ID:zk5zlAHc
しかし、キャリーフラグの話題でここまでスレ伸ばすのはすごいね
8bitのAVR信者っぽいんだけど
8bitだとキャリーフラグがないと何もできないからね
0586デフォルトの名無しさん
垢版 |
2019/11/30(土) 09:53:10.63ID:xhEM6aVw
結局、自分から言い出しといて挟まなきゃならない理由も説明してくれないのか。

まだほとんどコード書いたことない初心者なんだね^^
0588デフォルトの名無しさん
垢版 |
2019/11/30(土) 11:06:05.90ID:xhEM6aVw
>>587
自分で言い出しといて、答え、コード例は絶対に言わないのね。

そりゃコード書かないもんね、大学の人は。初心者だもん。
0589デフォルトの名無しさん
垢版 |
2019/11/30(土) 11:18:54.45ID:zk5zlAHc
パイプラインがストールするとか言うから
MIPSやRISC-Vならslt命令とbne命令の間に他の命令を挟めるよと言っただけ
自分で発言を誘っておいて意味もわからないんだな
0590デフォルトの名無しさん
垢版 |
2019/11/30(土) 11:28:29.70ID:xhEM6aVw
>>589
頓珍漢。ストールするのは条件ジャンプだから。挟んでもその後でmipsはストールする。
挟まなきゃならない理由の説明になってなし、並列化できるでなきいの例でもなんでもない。

話戻すよ。mipsは並列化できてフラグありCPUで並列化できない例を挙げてと言ってるんだよ。
0594デフォルトの名無しさん
垢版 |
2019/11/30(土) 11:49:35.35ID:xhEM6aVw
>>591
たった一つの例が全然例でなかったのに勝利宣言か。だいたいAVRもキミの好きなRISCだろう。

cmp
jb

並列化できない!! ←mipsでもできません

cmp
add
jb

mipsならこんなことができる!!

挟む理由は別になし。可読性が低下するだけ。
同じことしたいならadd、cmp、jbの順に書けばいいだけ。これで並列可。
しかもmipsのほうが遅いという。
0595デフォルトの名無しさん
垢版 |
2019/11/30(土) 12:20:15.39ID:WebQyLi7
cmpに時間がかかる(可能性がある)なら挟む
分岐なのでcmp結果はなるべく早く欲しい
当然命令順が速い方が実行順が速い可能性が高くなる

アセンブラに可読性?
99.99%のコードはコンパイラを使うから
そもそも可読性を考えて命令を作らない
0596デフォルトの名無しさん
垢版 |
2019/11/30(土) 12:54:50.65ID:WebQyLi7
キャリーフラグの典型的な用途
多倍長整数の加算

ADCを連続で行うが
この間にキャリーフラグを使う命令は入れられない

今時のCPUは整数命令を4個同時に実行出来るので
間に命令をいれないと性能の1/4しか活かせない
性能を活かすには4個パラにするか、
多倍長加算以外の処理を入れることになるが
キャリーフラグのせいでこれが出来ない

最大限に最適化する場合はSIMD命令を使うのだが
これにもキャリーフラグなんてものは無い
0597デフォルトの名無しさん
垢版 |
2019/11/30(土) 12:58:12.03ID:+5qlZFtZ
現状RISC-Vの性能はAMD64に及ばなくね?理論がどうであれ実証できなきゃ絵に描いた餅よ
IA-32は長らくクソと言わ続けているがIntelとAMDが競争しているおかげか
そのハンデをねじ伏せいまだに高性能プロセッサの一角だしな
0598デフォルトの名無しさん
垢版 |
2019/11/30(土) 13:04:28.68ID:WebQyLi7
こんな極端な例じゃなくても
実際の実行順に近い順番で命令を書く方が
アウトオブオーダーの制約に引っ掛かりにくく
性能を活かせやすい

実際の実行順で
キャリーフラグを変更する命令と
キャリーフラグを使う命令
の間に何も命令を実行しないなんてことは非常にマレ
あったとすれば、
それはCPUの能力を全く活かしてない糞コード
0599デフォルトの名無しさん
垢版 |
2019/11/30(土) 13:09:58.22ID:xhEM6aVw
>>595
> cmpに時間がかかる(可能性がある)なら挟む

また理由は書かないのか。まあ理由は分からないがMIPSはそんな可能性があるとは遅くて大変だな。
インテルの実装は速くなることはあっても遅くはならないから。いつになったらフラグで遅くなる例を出してくれるんだか。
まさか条件分岐でインテルやARMに勝つ気じゃないよね?
0601デフォルトの名無しさん
垢版 |
2019/11/30(土) 13:33:55.49ID:xhEM6aVw
>>600
煽る暇があったらフラグで遅くなる例をひとつぐらい出してよ。
128bit加算も条件分岐も全部MIPSのほうが遅い例ばかりじゃん。
0602デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:27:59.62ID:rGr6foFe
いつものAVR信者だからかまっちゃダメ
MIPSと聞くと毎回同じようにキャリーフラグの話を始める
いつも自分が正義だと思い込んでて他人の都合の悪い意見は全く無視するからね

http://rio2016.5ch.net/test/read.cgi/denki/1462177958/134
134 :774ワット発電中さん [↓] :2019/11/30(土) 14:53:33.69 ID:IRFNBB8m.net
またMIPS君が他の板で暴れて論破された模様TT

フラグで遅くなる例を出せと言われて一つも出せなかったらしい。
0603デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:30:00.80ID:AFPNe0zJ
>>574
そりゃ逃げ回るでしょ、アウトオブオーダーがどんな仕組みで並列に実行できるのか理解してないんだからw
こんなこと書いてるからな
>フラグは本来依存性の無い処理まで依存性が出てくる
>フラグが共通だから
これのどこがアウトオブオーダーによる制限なんだよw
間に挟めないのは元の命令アーキテクチャによる制限だって書いたよな

>>596
>今時のCPUは整数命令を4個同時に実行出来るので
>間に命令をいれないと性能の1/4しか活かせない
また出まかせをw
ここ数年インテルがリオーダーバッファのサイズとか強化してるのは何でだよ?
メモリアクセスのレイテンシの影響を軽減するためだろ
そういう状態ではカウンタとかポインタのインクリメントみたいな処理は前倒しで実行されるから、
間に命令を挟んだのと同じことになるよな
0604デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:44:48.54ID:WebQyLi7
分岐に必要な命令を先に実行するほど頭は良くない
単に実行出来る命令から実行するだけ
だからコンパイラがわざわざ順番を変える

フラグのせいでそれに大きな制限がつく

アウトオブオーダーが完璧ならコンパイラがわざわざ順番を変えたりループを展開したりしないから
同じ命令を使えば誰が書いても同じパフォーマンス

そこまで時代は進んでない
だからCコードで最適化してコンパイラが最適化してCPUが最適化してるの

フラグは8bitとか16bitとか、
非常に規模の小さなCPUにとっては便利だが
規模の大きなCPUでは足かせになる
使用頻度は減って
使用用途はほとんど分岐くらい

レジスタの数も少ないと問題だろ?
フラグも同じ
0605デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:46:59.54ID:WebQyLi7
>>596 の話
ADCを続けるのにどうやって他の命令を実行する?
そもそも記述が出来ない
1000回ADCを行うなら
その間にフラグ更新命令を一切記述出来ない
CPUの最適化以前の問題
0606デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:49:53.66ID:WebQyLi7
RCR/RCL による多倍長の1ビットシフトなんか最悪だ
依存性が途切れないので1クロックに1回しか出来ない

ADCもSBBも依存性が途切れないから
もっと頭の良い方法を使うんだけど
0607デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:50:53.74ID:WebQyLi7
まあそもそも可読性とか言ってる時点で話にならん
アセンブラなんか使わないで素直にCで書いてな
0608デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:53:07.85ID:AFPNe0zJ
ID:zk5zlAHcはID:4DEcYZGMやID:zk5zlAHcなんて擁護すると見識を疑われるぞ!

>>604
うわっ、酷っ!
>レジスタの数も少ないと問題だろ?
>フラグも同じ
結局これしか理解できてないから壮大な妄想を展開してたのかよw
0610デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:54:06.44ID:WebQyLi7
大体、
普段多倍長なんか使わんだろ
頻繁に演算でフラグを使う場面ていつだよ?
64bitありゃ99%は問題ないだろ
フラグの用途のほとんどが条件分岐だろうが

SIMDにフラグが無い理由を少しは考えろ
0611デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:57:07.46ID:AFPNe0zJ
>>606
>RCR/RCL による多倍長の1ビットシフトなんか最悪だ
>依存性が途切れないので1クロックに1回しか出来ない
これも突っ込みどころのある発言w
どうして依存性が切れないのか、やっぱり理解できてない
0612デフォルトの名無しさん
垢版 |
2019/11/30(土) 15:59:39.71ID:WebQyLi7
1000ワードの多倍長加算を100個

データはキャュシュにあるとして
どんなコードにする?

糞遅いコードしか書けないだろうね
0615デフォルトの名無しさん
垢版 |
2019/11/30(土) 16:05:29.45ID:AFPNe0zJ
どうして依存性が切れないのか理解できてないのがレベルが低いって言ってんだよ
WAW依存とか理解してるか?
0616デフォルトの名無しさん
垢版 |
2019/11/30(土) 16:29:11.13ID:WebQyLi7
>>612 の擬似コード

for (int i = 0 ; i < 100 ; i++){
. . CLC
. . for (int j = 0 ; j < 1000 ; j++){
. . . . ADC dest[i][j], src[i][j]
. . }
}

メモリアクセスや制御時間がゼロとしても
100 x 1000クロックかかる
ADCが前のADCの結果に依存するから
順番に処理をするしかない

RCL/RCRを使ったシフトも同じ
0617デフォルトの名無しさん
垢版 |
2019/11/30(土) 16:32:15.54ID:WebQyLi7
これはコンパイラの最適化やCPUのアウトオブオーダーでは解決出来ない

アセンブラで書こうがCで書こうが
頭が悪い人にとってはこれが限界
0619デフォルトの名無しさん
垢版 |
2019/11/30(土) 17:22:23.36ID:xhEM6aVw
そういうキャリーが必要な、前の計算結果が必要で依存する計算は、
キャリーがないCPUだとさらに効率は悪化するから例として意味がない。

128bitを1bit左シフト
SHL
RCL

mips64だとどういうコードですか?
andi
srl
sll
sll
or
みたいな? 大変でつね。他に便利な命令でもあるんですかね?RISCに対して失礼な質問でしたね^^
0620デフォルトの名無しさん
垢版 |
2019/11/30(土) 17:32:16.88ID:8+8CeiWg
> 頭が悪い人にとってはこれが限界

ほんとそのまんまでわらた
依存性を減らす、隠蔽するのが最適化の肝
ちょっとは考えてね
0621デフォルトの名無しさん
垢版 |
2019/11/30(土) 17:36:12.41ID:8+8CeiWg
当然>>616のままじゃダメ
MIPSだろうがARMだろうがx86だろうが

工夫するんだよ
その工夫がキャリーフラグを使うとちょっと難しい

いや、
そもそも>>616のままでも制御をフラグ無しでやらないといけないから大変だね
遅い命令を使って保存しておく????
0623デフォルトの名無しさん
垢版 |
2019/11/30(土) 17:45:13.95ID:8+8CeiWg
キャリーフラグの人は多倍長1ビットシフトを繰り返す
普通の人はバレルシフタをうまく使う
0624デフォルトの名無しさん
垢版 |
2019/11/30(土) 17:52:27.94ID:21OIT27J
一度に1000回もADCするとかよほど暇なアプリケーションなのだろうな
マイコンのADCと仮定すると速い物でも計0.5〜1msecくらいかかるだろう
単に移動平均が欲しいだけなら必要なコストはADC変換1回に付き加減算各1回+メモリアクセスですむんだし
0625デフォルトの名無しさん
垢版 |
2019/11/30(土) 19:36:02.39ID:8+8CeiWg
何で移動平均が突然?
多倍長の話だろ?

そもそも多倍長なんか普通は使わない
普通は64bitで収まる
だからキャリーフラグを使った足し算なんて普通はしない

キャリーフラグを使った演算は
8bit、16bit時代の、遅いCPU時代のなごりだ
0626デフォルトの名無しさん
垢版 |
2019/11/30(土) 21:00:54.84ID:xhEM6aVw
>>625
ARMは最初から32bitだし、AVRに至っては32bit時代に新規に開発された8bitCPUだし、
共に市場で成功したRISC CPUである。キミがキャリー使わないのは単にコード書かないからに過ぎない。
Cでif文でも書けばコンパイラが必然的に使ってしまう。
0628デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:20:20.00ID:jbs9cucn
>>626
ARMはともかくAVRって
1個ずつ順番にやるしかないCPUは>>616で良いんだよ
このコードが糞なのはスーパースカラーの話
つまり、現代の高速CPU全て

スーパースカラーでどうやって速くするか
SIMDでどうやって速くするか
ベクトルコンピューターでどうやって速くするか

頭が悪いと>>616が限界
0630デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:31:00.07ID:AFPNe0zJ
>そもそも多倍長なんか普通は使わない
とか書いておきながら100個の多倍長とか、ずいぶんと極端な例を持ち出すことw

ローテート命令が依存性を抱えてる理由に即答することもできずに、別の話題で誤魔化そうとしてるから
あんたがアウトオブオーダーをまともに理解してないのは確定的だな
これで究極の最適化だのほざいてたのかよw
0631デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:33:09.34ID:jbs9cucn
煽れば答えがもらえると思うのは間違い
レベルが違い過ぎて話にならんから無視するぞ
0632デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:34:55.48ID:FaWuMeWQ
>>607
「話にならん」が口癖の人には悪いけど、可読性は非常に大事。
MASMならマクロが使えるから、定型的な処理はマクロで書いておけばその処理が必要な部分は1行で書けるし、
if-elseマクロを使うだけでもだいぶわかりやすくなる。
http://shaw.la.coocan.jp/masm/control.php

特に他人が書いたソースをいじらないといけないときは可読性大事。修正や変更の手間が大幅に省ける。
0633デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:37:24.82ID:xhEM6aVw
>>629
頓珍漢なレスにマジレスしてやったらそれを理解せず頓珍漢なこと言われてもだな。
それともMIPSは1bitシフトとバレルシフタと命令が別なのかい? RISCなのにw

> キャリーフラグの人は多倍長1ビットシフトを繰り返す
> 普通の人はバレルシフタをうまく使う

とにかく煽りではなくコード見せてよ。
バレルシフタを上手くつかった任意bitのシフトを。キミは普通の人なんだろ?
0634デフォルトの名無しさん
垢版 |
2019/11/30(土) 22:44:56.42ID:AFPNe0zJ
>>631
俺が答えを知らないんじゃなくて、お前が知らないんだろw
煽られても答えることが出来ないからって、レベルが違うとかw
恥も上塗りしまくれば目立たなくなるともお思いで?
wwww
0635デフォルトの名無しさん
垢版 |
2019/12/01(日) 01:20:15.72ID:npZTl1ra
100個の多倍長の配列なんて極端な例を持ち出さなきゃ、普通にアウトオブオーダー実行されるってことだよな
でなきゃそんな欠陥CPUなんてスパコンで使うはずないだろうに

mov edx, 1

xor eax, eax
キャリーを変化させたい命令
cmovc eax, edx
ってやりゃ、キャリーフラグの結果をGPRに反映できるはずだから、以降は機械語の制限による
依存は切り離せるはずだよな
0636デフォルトの名無しさん
垢版 |
2019/12/01(日) 01:44:07.93ID:npZTl1ra
cmovcじゃなく、
adc eax, 0
でもいいか
こっちの方が余計なレジスタ使わなくていいし
0637デフォルトの名無しさん
垢版 |
2019/12/01(日) 02:42:43.59ID:rpSiZ7Ms
コンパイラに出力させると
例えば、15bitの左シフトはこんな感じ
  $3:$2←$5:$4 << 15
  dsrl  $2,$4,49
  dsll  $3,$5,15
  or   $3,$2,$3
  dsll  $2,$4,15

risc-vのRV64GCだとこう
  a1:a0←a1:a0 << 15
  srl   a5,a0,49
  sll   a1,a1,15
  sll   a0,a0,15
  or   a1,a5,a1

arm64だとこう
  x1:x0←x1:x0 << 15
  mov   x2, x0
  lsl   x0, x0, 15
  extr  x1, x1, x2, 49
0638デフォルトの名無しさん
垢版 |
2019/12/01(日) 02:43:56.72ID:rpSiZ7Ms
任意のシフトはこんな感じ
  $3:$2←$5:$4 << $6

  sll  $2,$6,0
  dsrl $3,$4,1
  nor  $7,$0,$6
  dsrl $7,$3,$7
  dsll $3,$5,$2
  andi $6,$6,0x40
  dsll $2,$4,$2
  or   $3,$7,$3
  movn $3,$2,$6
  movn $2,$0,$6

risc-vのRV64GCだとこう
  a1:a0←a1:a0 << a2
    and   a5,a2,64
    beqz  a5,.L1
    sll   a1,a0,a2
    li   a0,0
    jal zero, .L2
.L1:
    srl   a5,a0,1
    not   a4,a2
    srl   a5,a5,a4
    sll   a1,a1,a2
    or   a1,a5,a1
    sll   a0,a0,a2
.L2:
0639デフォルトの名無しさん
垢版 |
2019/12/01(日) 02:44:18.13ID:rpSiZ7Ms
arm64だとこう
  x1:x0←x1:x0 << w2
  mov   w4, 63
  sub   w5, w4, w2
  lsr   x4, x0, 1
  sub   w3, w2, #64
  cmp   w3, 0
  lsl   x1, x1, x2
  lsr   x4, x4, x5
  orr   x1, x4, x1
  lsl   x4, x0, x3
  csel  x1, x4, x1, ge
  lsl   x0, x0, x2
  csel  x0, x0, xzr, lt
0640デフォルトの名無しさん
垢版 |
2019/12/01(日) 11:18:31.61ID:sKSeAmO2
そういえば最近のx86は
典型的な条件ジャンプは
内部的に比較やテストとあわせて1個のuOP命令になる

内部的にはMIPSの条件ジャンプをリッチにした感じ
比較とブランチで2命令も費やしてたら
パフォーマンス的に問題だからね

分岐でも演算でも、
キャリーフラグの出番はもうほとんどない
0641デフォルトの名無しさん
垢版 |
2019/12/01(日) 12:25:49.37ID:rpSiZ7Ms
Intel® 64 and IA-32 ArchitecturesOptimization Reference Manual
64-ia-32-architectures-optimization-manual.pdf
248966-033June 2016
109ページ目3-12の3.4.2.2 Optimizing for Macro-fusionに書かれてるね
リンクはNGワードで貼れなかったのでググッてね
0643デフォルトの名無しさん
垢版 |
2019/12/01(日) 13:38:02.71ID:N3Tb7oIA
>>640
キミが有名なMIPS君かw
0644デフォルトの名無しさん
垢版 |
2019/12/01(日) 13:45:41.30ID:npZTl1ra
>>640
jcc命令の説明
77 cb JA rel8 D Valid Valid Jump short if above (CF=0 and ZF=0).
73 cb JAE rel8 D Valid Valid Jump short if above or equal (CF=0).
キャリーフラグは使われてるぞ
0645デフォルトの名無しさん
垢版 |
2019/12/01(日) 13:47:09.12ID:npZTl1ra
ちょっと見難いね
JA Jump short if above (CF=0 and ZF=0).
JAE Jump short if above or equal (CF=0).
0646デフォルトの名無しさん
垢版 |
2019/12/01(日) 14:13:26.95ID:rpSiZ7Ms
>>644
>>642にマクロフィユージョンで内部的に1命令になるって書いてあるじゃん
JA、JAEはTEST、AND、CMP、ADD、SUBがマクロフュージョン可能なようだね
0647デフォルトの名無しさん
垢版 |
2019/12/01(日) 14:21:48.12ID:npZTl1ra
>>646
間にフラグをいじらない他の命令挟むとフュージョン出来ないはずだし、
フュージョンした場合でも、フラグレジスタも一緒に更新するので、フラグを使うと考えていい
演算回路のキャリー信号を使わないということは、まず考えられないよ
0648デフォルトの名無しさん
垢版 |
2019/12/01(日) 14:22:09.47ID:p3Z7Nr0h
>>643
MIPS君が何者かしらんが
おれはx86/ARM/MIPS全てを愛する男
SH/RL78/C6000/C2000/PIC/AVR/RX
などなどいろいろと経験あり
0652デフォルトの名無しさん
垢版 |
2019/12/01(日) 14:33:05.42ID:npZTl1ra
>>650
なんで噛みついて来るんだ?
間にmovが入ったりしてもフュージョンすると思ってる?
こういう時は普通にフラグレジスタを参照するぞ
0653デフォルトの名無しさん
垢版 |
2019/12/01(日) 14:40:26.09ID:npZTl1ra
確かマクロフュージョンって、実行キューに入るときには別々のμOPsに分解されたはず
整数パイプと分岐ユニット用にね
0654デフォルトの名無しさん
垢版 |
2019/12/01(日) 15:01:21.03ID:rpSiZ7Ms
>>653
また分割しちゃったらマクロフィユージョンで統合した意味なくないか?

>>646のExampleのところにこう書かれてるね
Sandy Bridge microarchitecture enables more arithmetic and logic instructions
to macro-fuse with conditional branches.
In loops where the ALU ports are already congested,
performing one of these macrofusions can relieve the pressure,
as the macro-fused instruction consumes only port 5, instead of an ALU
port plus port 5.
0655デフォルトの名無しさん
垢版 |
2019/12/01(日) 15:30:27.00ID:npZTl1ra
>>654
そういや、分解されるのはマイクロフュージョンの方だったか?
ポート5でALUと分岐ユニットが一緒になってるから間違ってたかも、ゴメン
でも、フュージョン出来ない書き方も可能なはずなので、フラグ参照するパターンもあるはずだよ
0656デフォルトの名無しさん
垢版 |
2019/12/01(日) 22:01:05.21ID:N3Tb7oIA
>>648
MIPSマシン、RISC-Vマシンなんて手に入らないからMIPSの話はMIPSスレでよくね? ここ初心者板だよ? 

ほんとこんなところでスレチのMIPS、RISC-Vニュースコピペしないでくれるかな。
ここム板だよ。荒らしと変わらないよ。興味あるならMIPSスレのほう除くでしょ。
0660デフォルトの名無しさん
垢版 |
2019/12/01(日) 22:54:42.00ID:rpSiZ7Ms
RISC-Vが手に入るようになったからトランジスタ技術2019年11月号や
インターフェースの2019年12月号で特集やってるわけだが
0661デフォルトの名無しさん
垢版 |
2019/12/01(日) 23:20:53.64ID:rpSiZ7Ms
RISC-VはMaix Bit、MaixdunoならArduinoで使えるのでかなり敷居は低くなったぞ
価格も3000円から4000円程度
これらがダメというならAVRの話もダメということになるね
そもそもこんなに荒れたのは
>>529->>539の話があって、>>540を貼ったらAVR信者が食いついて荒らしただけ
0662デフォルトの名無しさん
垢版 |
2019/12/01(日) 23:26:12.86ID:npZTl1ra
MIPS君?って、
>フラグはアウトオブオーダーの妨げになるし
>並列化も出来ないから
って主張が完全崩壊して、当分は現れないんじゃないかな…
アウトオブオーダーの知識も色々とおかしくて、あれで最適化の講釈する度胸はないだろ
0666デフォルトの名無しさん
垢版 |
2019/12/02(月) 19:22:50.55ID:kmSxls5X
AVX512に慣れると、
他のコアがチープに見える
特に32bit〜64bitの中途半端なヤツが

京の次のヤツのARMってSIMD何ビットだっけ?
ちょっと遊んでみたい
0669デフォルトの名無しさん
垢版 |
2019/12/03(火) 11:32:29.72ID:g2sdmHcp
チープなやつは大体どれも変態だよ

C言語で記述不可能なのもあるから
PICは変態な中でもまだマシな方
0674デフォルトの名無しさん
垢版 |
2019/12/14(土) 02:42:04.15ID:er8xklWG
日本では特に間違って伝わってるからなぁ
想像するのがC言語やスクリーンエディタ機能組み込まれてた頃のBASICのGOTOっていう
0675デフォルトの名無しさん
垢版 |
2019/12/14(土) 07:46:40.45ID:6lStbnNy
古臭くて役にも立たない話をするのが大好きで、LARGEADDRESSAWAREやキャリーフラグで
大爆死した誰かさんがしれっと戻って来てるのか?
0676デフォルトの名無しさん
垢版 |
2019/12/14(土) 12:04:43.11ID:teIen0U1
GOTOがというより抽象化に関する教育の不足が問題なんじゃ
昨今のプログラミング教育も本質が見えているようには見えない
0677デフォルトの名無しさん
垢版 |
2019/12/14(土) 12:07:38.82ID:2PNj6NH4
歪んだ教育のせいで
ループ内で意地でも
continue, break, goto
を使わない人がいる

その為、
無駄な変数を使ったり
ループ条件が複雑になったり
本末転倒
0678デフォルトの名無しさん
垢版 |
2019/12/14(土) 13:25:49.98ID:TlZt0bii
breakにラベル指定出来なかったのはCの設計ミスやろ
0679デフォルトの名無しさん
垢版 |
2019/12/14(土) 13:34:05.64ID:JwYnIOEa
多重ループはgotoで抜ける
って事だろうけどね
gotoはラベル名を考えるのが面倒

break 2;
で2段階breakが出来ると良い
0680デフォルトの名無しさん
垢版 |
2019/12/14(土) 13:39:05.39ID:qH7KRmrQ
>>679
N88-BASICのような時代は、行番号があったからラベル名を考える必要が
なく楽だった。MASMの場合は、プロシージャローカルのラベル名が
使えたので、lab1:, lab2: のようにしておくと楽だった。
Cの場合、見た目的に「ラベルが浮く」現象が起きるのも問題。
0681デフォルトの名無しさん
垢版 |
2019/12/14(土) 13:44:49.72ID:qH7KRmrQ
BASICの場合、
1000 xxx
1010 if xxx > xxx then 1200
1020 xxx
1030 goto 1300
1200 xxx
のように書けて至って楽だったし、見た目も綺麗に書けた。

アセンブラの場合も
xxx proc near
   mov yyy,zzz
lab1:
   call aaa
lab2:
   dec ecx
   jnz bbb
xxx endp
のように命令の前には tab(0x09) 付けされ、ラベルと区別が付き易いのでとても
綺麗に書けた。ところがCの場合は、ラベルと命令の見た目のバランスが悪いので
問題となった。構造上の汚さよりもその問題の方が大きい。
0684デフォルトの名無しさん
垢版 |
2019/12/14(土) 16:23:54.51ID:qH7KRmrQ
>>683
こんな感じですか?
{
  {
  ラベル名1:
    if ( xxx < yyy ) {
      普通の文1;
    ラベル名2:
      普通の文2;
    }
  }
}
0691デフォルトの名無しさん
垢版 |
2019/12/15(日) 11:22:32.97ID:ymerGKQi
アセンブラは元々CPUに寄せてるのが普通で、人間に合わせるなんてこと考えてません。
人間がわかりやすいようにしたければマクロで補うなり、プリプロセッサ作るなどして工夫すればいいんですよ。
0693デフォルトの名無しさん
垢版 |
2019/12/15(日) 13:07:08.62ID:o9m7qUoD
ハーバードだろ
0694デフォルトの名無しさん
垢版 |
2019/12/15(日) 13:31:23.47ID:ymerGKQi
>>692
でもね、プロセッサ変わる度に覚え直すのは面倒だしつらいだろ。
面倒なものや難しいものをそのまま力業で押し通そうとするのはやっぱり頭悪いやり方。
賢い人なら、もっと頭使って少しでも使いやすく、わかりやすく変えていくもんだと思うんだよね。
0697デフォルトの名無しさん
垢版 |
2019/12/15(日) 19:26:43.84ID:ymerGKQi
>>696
Cが対応しているプロセッサならそれ使えばいいけど、同じ処理をアセンブラで書くのとCで書いたのでは実行ファイルのサイズが大きく違う。
Cは余計なランタイムルーチンがリンクされて無駄に太る。Cで書いてもアセンブラで書くのとほとんど同じサイズになる処理系があればその方が良い。
そして、なければ作るしかない。覚えにくいニーモニックを頑張って覚えるくらいなら、そういう処理系を作ることに労力を使ったほうがいいんじゃないかな。
0698デフォルトの名無しさん
垢版 |
2019/12/15(日) 19:42:57.22ID:5kgRNS4L
今時マイコンですら結構な容量のフラッシュROMを積んでいるし
高級言語に由来するフットプリント増が問題になるケースは少ないと思うが
高いリアルタイム性が要求されたり重い処理をするケースはアセンブラで書く場合がある
0699デフォルトの名無しさん
垢版 |
2019/12/15(日) 20:20:04.05ID:5sPbacoo
>>697
需要がないプロセッサは作らない
それだけ

変態アーキテクチャは理由があってそうなってる訳だし
普通のCPUならC/C++で使いやすいように整備されてる

Cランタイムサイズが問題になるCPUだと
ランタイムも小さく出来るのが普通
(printf、malloc を使わないなど)
0704デフォルトの名無しさん
垢版 |
2020/01/14(火) 15:59:36.64ID:uFo9dhko
68000君は居ないようだな。残念だ
C言語も神が作ったのではない、breakやcontinueがどこに飛ぶのか分からん時はある。
入門書を信じ込んだ狂信者、原理主義者のような、痛い目に会ってない素人は結構いる。
0705デフォルトの名無しさん
垢版 |
2020/01/14(火) 19:13:53.43ID:VTSZmZmV
>>704
> breakやcontinueがどこに飛ぶのか分からん時はある。
そんな経験はないなあ。普通はCの仕様通りに動く。
Cの仕様通りに動かないとしたらそのCコンパイラのバグだと思いますよ。
もし本当にわけがわからない動作をしたときはテストプログラムを書いてどう動くか調べたり
アセンブラソース出力して見てみればいい。
0707デフォルトの名無しさん
垢版 |
2020/01/15(水) 12:54:18.67ID:mdjDjCL2
素朴な疑問なんだが逆アセンブラのラベルってどうやって生成されるの?
レジスタ間接ジャンプのジャンプ先アドレスなんて実行してみないと判らないような・・・
0709デフォルトの名無しさん
垢版 |
2020/01/16(木) 05:34:03.43ID:I1VMveuP
>>705
>そんな経験はないなあ。普通はCの仕様通りに動く。
多重ループ脱出やifやなんやらのネストでどこに行くか分からなくなる事は無かったんか
Cの経験浅い人は、そういうことが分からないんだろうな。
0712デフォルトの名無しさん
垢版 |
2020/01/16(木) 23:36:50.30ID:GgmseacB
>>709
複雑なものを複雑なままコードにするからそうなる。
多重ループと言ってもせいぜい2重か3重だし、それ以上深いループになるようなコードだったら
そもそも考え方が悪いからシンプルになるように書き直す。中身をサブルーチンに追い出して、
ループ構造と脱出が一目でわかるようにしても良い。
ifのネストも同様に、細部の条件を洗い出してパラメータを変えて呼び出すだけで動くようにする。
そうすればif文を見なくていいしそれぞれ1行で呼び出せる。
とにかくできるだけ構造がシンプルでわかりやすくなるように工夫することだよ。
0713デフォルトの名無しさん
垢版 |
2020/01/18(土) 09:17:15.53ID:bQ1xI4/b
>>709
そのためにC言語にはgoto文があるわけだが
別にスパゲッティプログラム書くためにあるわけじゃないぞ
0716デフォルトの名無しさん
垢版 |
2020/05/14(木) 17:51:17.70ID:f1vNNG/3
まったくの初心者なのですが、アセンブリ言語を理解できるようになりたいです。
入門サイトなどを探しても自分が探しているCPUを取り扱っている物は見つかりませんでした。
まだCPUの仕組みもよく理解していないような状態なので、種類に拘らずそのような入門サイトなどで勉強した方がいいのでしょうか。
一通り学習を終えた後、別のCPUの言語でもすぐ対応できますか?
iosアプリのリバースエンジニアリング をしてみたいと思っているのでarm64のコードを理解できるようになりたいです。(用語などの使い方が間違っていたらすみません。)
0717デフォルトの名無しさん
垢版 |
2020/05/14(木) 17:59:48.21ID:xR/PZA9p
マルチ死ね
0718デフォルトの名無しさん
垢版 |
2020/05/14(木) 19:21:25.82ID:FSEZeoAj
情報処理資格の教科書から、始めた方がよい。
CASL 2 という仮想アセンブラもある

仮想アセンブラとは、各メーカーごとの実際のアセンブラではなくて、抽象的なもの

仮想アセンブラでは、LLVM が最も有名
0719デフォルトの名無しさん
垢版 |
2020/05/15(金) 10:21:28.00ID:QqRlTuRs
動機を当ててやるか。ゲームを改造して無双したいのだろう。
だがそんなの対策済みで無駄なことだ。
0720デフォルトの名無しさん
垢版 |
2020/06/17(水) 20:16:42.08ID:mLHHLomt
実プロセッサのアセンブラを学ぶのに仮想アセンブラって役立つか?
LLVMなんてレジスタ数無制限だしスタック無しでも処理を書けるだろ
実際のプロセッサでそれは現実的ではないしスタック操作はボトルネックにもなっている
0722デフォルトの名無しさん
垢版 |
2020/06/21(日) 16:12:29.75ID:rRP2z2l8
MPUそのものは仮想でもエミュがあってそこそこ実用になるなら良いんじゃない?
0724デフォルトの名無しさん
垢版 |
2020/06/30(火) 20:45:59.73ID:2de2B/rP
コンパイラにアセンブラ出力させてみた結果
8bitのアセンブラが簡単なんて嘘

Cソース
https://pastebin.com/bWfLhn8Y

8bit MSX-C Ver1.1 アセンブラ出力
https://pastebin.com/Bzt3fFaX

16bit Turbo-C Ver1.5 アセンブラ出力
https://pastebin.com/y82ifpxs

64bit Ubuntu 18.04 x86_64 gcc-7.4.0 アセンブラ出力
https://pastebin.com/PTuEv5uL

64bit Ubuntu 20.04 ARM64 gcc-9.3.0 アセンブラ出力
https://pastebin.com/9N4eKWeg
0725デフォルトの名無しさん
垢版 |
2020/06/30(火) 20:50:56.99ID:2de2B/rP
ちなみにgccでは
int func01() __attribute__((noinline,noclone));
とやってインライン展開を抑制してます
0727デフォルトの名無しさん
垢版 |
2020/06/30(火) 21:05:11.63ID:dU7zENbL
>>724
Cのintは16bitだから、8bit CPUではint変数を2回に分けて転送しないといけない。
複雑になって当然。
0728デフォルトの名無しさん
垢版 |
2020/06/30(火) 21:11:37.45ID:e6PapWOV
単純な命令しかなくて命令数も圧倒的に少ない8bit
複雑な命令がたくさんあって命令数も1000を越える64bit
0730デフォルトの名無しさん
垢版 |
2020/07/01(水) 04:09:06.24ID:GZMydJ4F
>>726
8bit整数を扱うだけで済む処理なら簡単だが、8bitを超える可能性がある処理だと途端に面倒になる。
8bitなんてすぐ溢れる。
0732デフォルトの名無しさん
垢版 |
2020/07/01(水) 10:54:24.39ID:dk2qwU4W
簡単さだったら新しいCISCに分があるんじゃね
ttps://uploader.purinka.work/src/17167.png
R0はスタックポインタ。呼び出し規約の都合上引数の一部が
スタックに積まれている以外はamd64と同じ感じか

同じ8bitでも8051とAVRじゃ大分違うと思う
0733デフォルトの名無しさん
垢版 |
2020/07/01(水) 11:12:01.44ID:BWQBxkNi
命令を覚える命令を使うのが簡単か
同じ機能を実現するのが簡単か

で結果が180度違う
0734デフォルトの名無しさん
垢版 |
2020/07/01(水) 11:14:42.34ID:BWQBxkNi
8bitCPUのソフトエンジニア
64bitCPUのソフトエンジニア
どちらがより多くの知識や経験が必要か

一般的には64bitの方が必要
0739デフォルトの名無しさん
垢版 |
2020/07/02(木) 08:31:24.65ID:RyBCtyYa
8bitが簡単と言われるのは命令の数が限られてるのと、簡単なことしかしないから
64bitでもよく使われる限られた命令だけ使って、8bitと同じことをやれば
8bitよりも簡単
実際は周辺や割り込みコントローラなんかもリッチになるので大変だけどね
Arduinoみたいにそのあたりを意識しないなら64bitの方が8bitよりも簡単
0743デフォルトの名無しさん
垢版 |
2020/07/02(木) 19:30:02.70ID:1S4E8SKc
アセンブラでしか書けない特殊処理(特殊命令、特殊レジスタへのアクセスなど)
速度やリソースのチューニング
趣味
0744デフォルトの名無しさん
垢版 |
2020/07/02(木) 20:08:46.86ID:L2HGsVdw
まあ趣味だな。Cで書けない処理をアセンブラで書けたら「やった」て気になるしな。
0746デフォルトの名無しさん
垢版 |
2020/07/02(木) 20:31:36.38ID:L2HGsVdw
趣味だからどういう処理でも自分が満足できればそれでいいんじゃね?
簡単な処理から始めてだんだん難しい処理に挑戦するのも面白いし
0748◆QZaw55cn4c
垢版 |
2020/07/02(木) 21:30:53.96ID:L13EtRzW
仮にアセンブラの本を書くとして、その題材になにを選ぶか、アセンブラだからこそできる!というナイスな題材がほとんど思いつかないのです…
0749デフォルトの名無しさん
垢版 |
2020/07/02(木) 22:24:08.15ID:L2HGsVdw
思いつかないってことは、本当にやりたいと思ってないってことだろうな。
たとえば部屋で飼ってる猫の様子を出先から監視したいと思ったらArduinoとカメラユニットを組み合わせて
スマホから見られる制御ソフトを作るだろう。
0750◆QZaw55cn4c
垢版 |
2020/07/02(木) 23:09:16.80ID:UiUhO26q
>>749
それはアセンブラだからこそできる、という題材ですか?
0754デフォルトの名無しさん
垢版 |
2020/07/02(木) 23:38:56.48ID:dBIHsFi5
ペリフェラルAとペリフェラルBを同期させて動かしたいなんて場合はアセンブラの使用を検討する
0755デフォルトの名無しさん
垢版 |
2020/07/02(木) 23:40:30.23ID:1S4E8SKc
えらい抽象的だな
タイミングにシビアなのはコンパイラに依存しないようにアセンブラで書くってのはある

もちろんシビアな部分だけ
0758デフォルトの名無しさん
垢版 |
2020/07/03(金) 07:56:44.00ID:jbweNl0h
最近ではSIMDやDSP命令はCの文法で記述出来るのが普通
もちろんガチガチのチューニングはアセンブラが一番だから
結局チューニングという範疇
0759デフォルトの名無しさん
垢版 |
2020/07/03(金) 17:33:03.39ID:Rc6pK0Eu
>>750
俺は「アセンブラだからこそ」という制限など付けていない。そういう制限はあんたが勝手に付けたものだ。
作りたいものを作る。それが趣味だ。
違うと思うなら自分で考えてアセンブラだからこそというものを作ればいい。
0760デフォルトの名無しさん
垢版 |
2020/07/03(金) 17:34:28.08ID:Rc6pK0Eu
>>753
趣味なんだから適すかどうかは関係ない。適さないと思うなら作らなければいい。
人それぞれだ。
0761デフォルトの名無しさん
垢版 |
2020/07/03(金) 18:57:27.44ID:C0RVqI6W
趣味ならアセンブラを使う理由なんて何でも良い
でもどうせならアセンブラを使うことでメリットが何かしら得られる方が良い
そのメリットは大きい方が良い
と思うのは普通かと
0762デフォルトの名無しさん
垢版 |
2020/07/03(金) 19:34:45.09ID:Rc6pK0Eu
>>761
趣味は一般的なメリットなんか考えてたらできない。
鉄ヲタなんか、自分で電車運転したいためだけにパソコンのシミュレータを自作してる。
それも20年もかけて作って値段は0。タダで配ってる。金銭的なメリットはゼロだ。
窓から見える信号機や駅のデータも手間暇かけて現地に行ってパソコンのデータに変換してる。
運転席の計器類やすれ違う電車のモデルやデザイン、色まで正確に再現してる。
とてもこれだけの手間に見合うメリットがあるとは思えない。
でもこれだけの無駄をしてもやりたいのが趣味なんだよ。
鉄ヲタがアセンブラを使うとしたら、電車が動くスピードが少し遅く感じるから本物と同じくらい反応を早くしたいと
思ったらすぐ使うだろう。とにかくやりたいからやる。それ以外のことは考えないのが趣味だよ。
0764デフォルトの名無しさん
垢版 |
2020/07/03(金) 19:52:48.87ID:v8523RMt
再現性がメリット
ならそれでいいじゃん

アセンブラを使うことで
高速化とか
リソースの節約とか
それもメリット

高速化もせず
リソースも変わらず
質が落ちる
だと何のためのアセンブラ?
0767デフォルトの名無しさん
垢版 |
2020/07/15(水) 00:32:33.69ID:0MCF5KaT
amd64+Linuxでアセンブラを始めたのですが、スタックの状態を勘違いしてのバグや
システムコール時のレジスタの退避し忘れのバグ等に悩まされてます

スタックの利用状況を分かりやすく表示してくれたり、レジスタの状態をチェックしてくれたり
するような、統合開発環境みたいなのはありませんでしょうか
0769デフォルトの名無しさん
垢版 |
2020/07/15(水) 12:20:50.44ID:cL9c5hZ8
慣れたら悩まなくなる
0770デフォルトの名無しさん
垢版 |
2020/07/15(水) 14:03:15.88ID:p6AIoBG7
アセンブラだと自己書き換えコードが出来るぞ
それによる考えられるメリットは様々あり、ここでは書きにくいこともあるw
あと、正確なことは分からんが、OS開発ではアセンブラがしばしば使われていて、特にブートローダーの開発で使われていると聞いたことがあるな
他にはマイコンだとアセンブラの方が開発しやすいこともあったりするのか?知らんけど
俺は、スレッドセーフなプログラミングにはアセンブラの知識が不可欠だと思っているが、これは他者の意見も聞きたいところだな
他にもアセンブラでしか出来ないことはあるのにアセンブラは趣味の為ときたもんだ(怒)
まずコンパイラは確実
エミュレータなんかもそうじゃないのか?知らんけど
0771デフォルトの名無しさん
垢版 |
2020/07/15(水) 14:24:49.32ID:miBvJk/V
>>767
Linuxでは知らんが、VSのデバッガだと、EAXなどのマシンレジスタの内容を常時
表示できる。
スタックに関しては、push、pop を組にすることと、ちゃんと数える習慣を
付けるしかない。
アセンブラは、言語仕様は簡単に思えるかもしれないが、頭脳が必要。
それはちょうど、数学が小学生でも理解できる四則演算だけを組み合わせているだけ
なのに、大部分の人がどこかで難しくなってしまうのと同じようなもの。
0773デフォルトの名無しさん
垢版 |
2020/07/15(水) 14:41:03.67ID:cL9c5hZ8
知能は文章に滲み出る
0774デフォルトの名無しさん
垢版 |
2020/07/15(水) 15:59:06.15ID:p6AIoBG7
知能はコードに滲み出る
0777デフォルトの名無しさん
垢版 |
2020/07/15(水) 18:23:23.15ID:bZTTdNA2
今時のGUIなデバッガだったらブレーク時にスタックやレジスタの内容を表示できるのは普通じゃね?
個人的にはパイプラインの動作状況を表示してくれるデバッガとか欲しいわ
依存関係に起因するNOP率とか、原因となっている命令の特定とか
0780デフォルトの名無しさん
垢版 |
2020/07/15(水) 18:51:31.23ID:miBvJk/V
>>779
違う。
俺は数学は優秀なほうだ。
0784デフォルトの名無しさん
垢版 |
2020/07/15(水) 19:10:04.26ID:p6AIoBG7
アセンブラに詳しい人はスゴい人多いから失礼な態度はとらない方がいいと思う
0785デフォルトの名無しさん
垢版 |
2020/07/15(水) 19:16:51.08ID:r/dLTGHk
>>767
アセンブラだからと言って人間が1から10まで考えなくてもいいんだよ。
間違いやすい処理はできるだけソフトやツールにさせるように考え方を変えればいい。
スタックの状態が間違いやすいと思うなら、スタックを管理するマクロを組めばいいし、
レジスタ退避を忘れるなら、レジスタ退避するマクロを組んでそれを使えばいい。
0786デフォルトの名無しさん
垢版 |
2020/07/15(水) 20:52:17.63ID:LyK3DjqL
その昔8051用のソフトをフルアセンブラで開発したことがある。デバッグは8個のLEDのみ
1500程度のコードだけどスタックや汎用レジスタの操作で苦労した記憶はないな
ペリフェラルの使い方等は大苦戦だったが

>>767は何を作っているのだろうか。IA-32ならともかくAMD64ならレジスタ本数も多いし
複雑なスタック操作をする機会は多くないと思うんだが
0788デフォルトの名無しさん
垢版 |
2020/07/16(木) 12:38:48.59ID:Bj5j4Y6i
謎の隠しコマンド連発するやつか
0794デフォルトの名無しさん
垢版 |
2020/07/16(木) 20:09:12.31ID:ICgJPJoU
今のアセンブラの需要って
・OS等の低レイヤーの処理をする
・高速化。1クロックでも節約したい
・リアルタイム。nクロック後に○○を実行する必要がある
こんなもんか?
0800デフォルトの名無しさん
垢版 |
2020/07/17(金) 02:55:00.98ID:xni+keKD
>>798
この業界では、アセンブラが使える人と使えない人ではやはり使える人の方が尊敬されるよね
0801デフォルトの名無しさん
垢版 |
2020/07/17(金) 06:35:47.52ID:CFzyXZw3
そういう歪んだ価値観のせいで
アセンブラじゃなくて良い所までアセンブラにするアホがいる
0802デフォルトの名無しさん
垢版 |
2020/07/17(金) 11:02:40.02ID:hPmghiPz
役に立ってる人は忙しいのでわざわざこんな辺鄙なところに描き込みに来る暇がない
自分も役に立ってない
0805デフォルトの名無しさん
垢版 |
2020/07/17(金) 14:04:20.27ID:xni+keKD
>>801
Cが得意だと何でもCで書こうとする。
アセンブラが得意だと何でもアセンブラで書こうとする。
プログラマなら良くあること。
アセンブラがそれほど得意でない人が見たら余計なことと思うんだろうけど。
0807デフォルトの名無しさん
垢版 |
2020/07/17(金) 14:36:42.77ID:R70AGkgr
PICマイコンみたく用途が限られてると、返ってアセンブラの方が短かったりする。
0808デフォルトの名無しさん
垢版 |
2020/07/17(金) 15:01:36.87ID:xXsIieN6
PICよりAVR
0809デフォルトの名無しさん
垢版 |
2020/07/17(金) 16:45:31.89ID:mOeBhMfJ
おいらがマシン語勉強した時(Z80A)ニモニック表見て作ってたね
相対ジャンプなんか手で計算して 今でもコード覚えてるよ LD A = 3E とか LD Bは06とか
アセンブラが手に入った時はなんて便利なんや〜と感動した
当時は子供でまさか仕事でもアセンブラ組むとは思わなかったけどね
0810デフォルトの名無しさん
垢版 |
2020/07/17(金) 17:42:45.57ID:zYg36R0O
http://www.yamamo10.jp/yamamoto/comp/Z80/instructions/index.php#LOAD08
A や B にイミディエイト値を入れる場合
00DDD110
DDD はレジスタ番号
B=0, C=1, D=2, E=3, H=4, L=5, A=7
LD B,n は 00000110 (06), n
LD A,n は 00111110 (3E), n
なんで DDD=6 は飛んでるんだっけ
0813デフォルトの名無しさん
垢版 |
2020/07/17(金) 21:14:06.39ID:2HBm6uJU
>>806
他人の評価などどうでもいい。俺もそんな古くさい見方しかできないあんたを三流と言ってあげよう。
0816デフォルトの名無しさん
垢版 |
2020/07/18(土) 13:49:01.14ID:HDs6SbLj
>>814
昔の事だったし、資料が手元に無いが、原則論として
DDDとかのレジスタ番号の1つとして、(HL)が書いてあり、
それがDDD=6だったと思う。
ただし、原則論なので、全ての命令でDDD=6にすれば必ず合法で、
(HL)になるという意味ではない。
0817デフォルトの名無しさん
垢版 |
2020/07/18(土) 13:51:52.21ID:HDs6SbLj
>>816
リンク先のページでも、
INC r; DEC r; LD r1,r2; LD r2, r1 においても、DDD=6は、(HL)の命令に該当
していることが分かる。
0819デフォルトの名無しさん
垢版 |
2020/07/18(土) 14:24:37.73ID:HDs6SbLj
AND, OR, XOR, ADD, ADC, SUB, SBC, CP,
やローテート、シフト命令でも、レジスタ様の命令で、
レジスタ番号を6にすると、(HL)に対する命令と同じ
マシン語になっていることが分かる。
0820デフォルトの名無しさん
垢版 |
2020/07/19(日) 04:45:05.98ID:1aVreze3
x86_64のアセンブラを始めようと思ってるのですが、レジスタの使い方を教えてください

以前、80286の頃だと、たとえばECXレジスタはカウンタ用に使うものだったと記憶してますが
x86_64だとほぼもう汎用レジスタとして使えるように見えます
gccなどもx86_64用でもそういうコードを出力するようです

昔の用途での使い方について、どれくらい意識した方がよいのでしょう
0821デフォルトの名無しさん
垢版 |
2020/07/19(日) 10:17:20.71ID:TvRHHtME
>>820
CPUの世代によっては、loop 命令は、
dec ecx
jnz ラベル名
とするよりも遅いことがあるので、後者の書き方の方が良い。
その意味で、ループカウンタを入れるレジスタとして、ecxにこだわる必要はない。

ただし、rep movsd などでは今でもカウンタが ecx に固定されている。

それ以外の場面では、ecxは、他の汎用レジスタと同じと考えてよい。

なお、ebpは汎用レジスタとしては使わず、スタックフレームの先頭アドレスを保持して、
ローカル変数をアクセスするために使うことが原則。
ただし、ローカル変数をebpの代わりにespを介してアクセスすることによって
ebpを汎用レジスタとして使う流儀も有り得る。
その場合は、push,pop命令によってespが変化してしまうので注意が必要となる。
なお、masmのlocalやarg擬似命令は、ebp方式を前提としている。

edi,esi は、movsd で使うことは意識しておく。
edx,eaxは、div命令で使うことを意識しておく。
edi,esi,ebpは、関数呼び出しで保存されるが、eax,ebx,ecx,edxは保存されないことを意識しておく。
eaxは関数呼び出しの戻り値になることを意識しておく。
0822デフォルトの名無しさん
垢版 |
2020/07/19(日) 10:18:46.24ID:TvRHHtME
>>821
さらに、dec reg 命令より、sub reg,1 の方が速いことがある。
前者は2クロック、後者は1クロック。なので、loop文は、
sub ecx,1
jnz ラベル名
と書くのが最良。
0824デフォルトの名無しさん
垢版 |
2020/07/19(日) 12:36:44.38ID:h5vFOzT4
レジスタが増えてるし
SIMDレジスタもあるんで
自由度は高い

MULとDIVは相変わらずRAX, RDX縛りがあるけど
0826デフォルトの名無しさん
垢版 |
2020/07/19(日) 14:46:51.74ID:1aVreze3
820です

回答ありがとうございました

ABIやライブラリ等での使い方・縛りを考慮して使うようにすると、
やはりそれぞれのレジスタをアキュムレータ、カウンタ等として使う、
というのを指針にした方がよさそうですね
0827デフォルトの名無しさん
垢版 |
2020/07/19(日) 15:35:41.18ID:AazHQwx2
>>826
いや、普通の命令文に対する繰り返しのカウンタとしては、ecxを意識する必要はない。
計算のアキュムレータとしても、eaxを意識する必要も余りない。
余りを求める割り算だけは特殊。
0830デフォルトの名無しさん
垢版 |
2020/08/03(月) 23:51:00.41ID:f8ly6bXL
ttps://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%89%E3%83%AC%E3%83%83%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%A2%E3%83%BC%E3%83%89
>アドレッシングモード
>既に使われなくなったアドレッシングモード
>メモリマップド・レジスタ
???国内なら78K0R(現RL78)、海外でもMSC-51(現EFM8BB1)とかはCPUのレジスタがメモリ空間にマッピングされている
いずれも現行製品では
0831デフォルトの名無しさん
垢版 |
2020/08/04(火) 10:47:29.79ID:DzQriKoF
6809の0-255あたりのやつのことかな
0832デフォルトの名無しさん
垢版 |
2020/08/04(火) 10:48:39.15ID:DzQriKoF
まあ同じことなんだろうけど
「CPUのレジスタがメモリ空間にマッピングされている」
というより
「メモリ空間がCPUのレジスタにマッピングされている」
というイメージ
0834デフォルトの名無しさん
垢版 |
2020/08/04(火) 12:45:04.95ID:g9THIEhB
ttps://ednjapan.com/edn/articles/1908/28/news026_3.html
STMはレジスタとSRAMの構造が違うらしい
理由からすると多くのCPUが同じ事やってそう
0836デフォルトの名無しさん
垢版 |
2020/08/04(火) 15:05:26.21ID:z2HwYjyf
>>830
> CPUのレジスタがメモリ空間にマッピング
て具体的にどうやるんだろ?と思って調べてみた。
CPUのアドレスバスを監視して、レジスタにアクセスがあったのを検知したら、
それにマップされてるメモリにも同じようにアクセスするってことをしてると。なるほど。
0837デフォルトの名無しさん
垢版 |
2020/08/04(火) 15:22:33.51ID:CK7AS0VE
>>836
そういうことではなく、レジスタをアドレス空間にマッピングしているCPUは、
例えば、アドレス空間の 0〜255 番地の部分をレジスタ専用に
して、CPUの外部のアドレスバスには信号が出ないようにしていることが多い。
そして、
mov [0],値
と書くと、r0 に「値」を書き込むようにCPUが設計されていて、
外部のDRAMなどには全く信号が送られないようになっている。
0838デフォルトの名無しさん
垢版 |
2020/08/04(火) 15:30:51.43ID:z2HwYjyf
>>837
そういうのもあるだろうけど、それは最初からそういう設計にしているからそう動くということだよね。
アドレス空間にある入出力領域は固定的である必要はないので、バスに出た信号をどう処理するかは
設計者が自由に決められるはず。なので、バスに出た信号をメモリだけに送ることもできるし、
CPUとメモリ両方に送ることもできる。用途に合わせればいいということかと。
0839デフォルトの名無しさん
垢版 |
2020/08/04(火) 15:34:19.50ID:CK7AS0VE
>>838
「レジスタをアドレス空間にマッピングしているCPU」
というのは、最初から設計されているCPUのことだと思うぞ。
実際、ポケコンのCPUもそんな感じだった。
0840デフォルトの名無しさん
垢版 |
2020/08/04(火) 16:20:06.60ID:z2HwYjyf
>>839
設計者が最初からそう設計したのならそうだろうね。
固定的である必要がないというのは、設計するとき設計者がどちらでも選べるという意味だよ。
0843デフォルトの名無しさん
垢版 |
2020/08/17(月) 08:09:56.01ID:tzd42ouk
LLVMが吐き出したx86-64アセンブラコードを入力とするツールを作りたいのですが
このアセンブラコードの文法に関する資料って何処にあるんでしょうか
ttps://llvm.org/docs/Extensions.html
ttps://sourceware.org/binutils/docs/as/
あたりにも各命令をどのように記述するかまでは載っていないように見えるのですが・・・
0846デフォルトの名無しさん
垢版 |
2020/08/17(月) 11:37:24.90ID:NVTg5S9X
>>843
LLVMツールの出力する、native の x86 や x64 のアセンブリコードは、
試してみる限り、masm 形式ではない。
見た目はgccの形式に似ている。
LLVMのarm版が出力したnativeアセンブリコードは、gccのgasが解釈して正しくobjファイル
までアセンブルできたことがある。
x86 や x64 の場合は、そこまでは試していない。
0847843
垢版 |
2020/08/17(月) 12:59:34.65ID:WGW93JMF
ぶっちゃけパーサーをどう作るかって所なのですが

>>844-845
そうなのですが
1.CPUのマニュアルの命令表記とアセンブラの命令表記は例外なく一致するのか
 基本的にはマニュアル通りで良さそうですが表記に揺れがあった場合困る
2.リファレンスはAMDかIntelか
 この命令セットを設計したのはAMDだし処理系の対応もAMD64が先行していたはず
あたりはイマイチはっきりしないです

>>846
吐かれるアセンブラコードはGASベースで独自のディレクティブが追加されているように見えますね
0848デフォルトの名無しさん
垢版 |
2020/08/18(火) 01:12:29.19ID:xqTakpBf
>>847
命令表記は、8バイトのオペランド(や型)を表すのにdqwordとowordで表す
2つの流儀がある。
さらに、mmwordを使う流儀もあるが、浮動小数点演算のx87の文化では
浮動小数点でも専用の型名は無くて、dwordでfloat、qwordでdoubleを扱う
流儀があった。
そこにxmmやmmxのためだけにmmwordを持ってきた意図やセンスは
賛否が分かれるところだと思う。
0849デフォルトの名無しさん
垢版 |
2020/08/18(火) 01:28:37.97ID:xqTakpBf
>>847
x64のリファレンスは、原則的にAMDで、AMDにも詳しいマニュアルがある。
命令表記は、絶対アドレス addr に対する間接参照で、昔は、[addr]と
表記していたものが、x64だと、マシン語レベルでは絶対アドレスを埋め込まずに、
ripからの相対アドレスrel_addrを用いて、[rip+rel_addr]のような意味になっている
があるが、アセンブラレベルでそれを表記する時、どうするかと言う問題がある。

masmだと昔から、
mov eax,MyWork1
・・・
ret
MyWork dd 1234
と書いてきた。普通のアセンブラなら、
mov eax,[MyWork1]
・・・
ret
MyWork: dd 1234
と書くところを。
しかし、rip相対になった場合、
mov eax,[rip+MyWork]
と書くと意味に合わないし、かと言って、
mov eax,[rip+rel MyWork]
と書くのも長くなる。意味的には、Masmだと
mov eax,MyWork
なのだが、マシン語レベルでは、絶対アドレス/相対アドレスのどちらで表現されるか、
明確に表すことはできなくなるジレンマがある。
0850デフォルトの名無しさん
垢版 |
2020/08/21(金) 15:25:03.93ID:EskYTmRE
destにメモリを指定できる命令ってパイプラインをストールさせやすいように思うけどそんな事はないの?
x64だと
ADD r/m64,r64
みたいなの
0851デフォルトの名無しさん
垢版 |
2020/08/21(金) 20:30:50.01ID:+dwilF/E
確かにストールしやすいとは言えるが影響度合いはプロセッサ次第で、そういう命令を持ったプロセッサはちゃんと考慮した設計がされている。

例えばOut of Order実行を行うプロセッサはパイプラインに結果書込み待ちをするキューを持ったステージがあって、メモリ書き込み前に後続の命令を実行可能だから単純にストールはしない。

前後の命令に依存があればストールするのはレジスタ相手でも同じことだし、命令でロードとモディファイとストアを分けても実行する内容は同じなのだから、結局はプロセッサアーキテクチャ毎に最適化が必要なことには変わりがない。
0852デフォルトの名無しさん
垢版 |
2020/08/22(土) 00:25:14.47ID:Rco6UMRM
インテル(R) 64 アーキテクチャーおよび IA-32 アーキテクチャー最適化リファレンス・マニュアル
を良く呼んだら書いてあったわ
> 一般的に、各命令を構成するマイクロオペレーション(μOP)の数を考慮し、単一マイク
> ロオペレーション(μOP)の命令、4 マイクロオペレーション(μOP)未満の単純な命令、
> マイクロシーケンサー ROM が必要な命令の順で優先して、命令を選択すると良い。
> 〜
> ・複数のマイクロオペレーション(μOP)からなる一連の命令を分割できない場合は、
>  同等の異なる命令シーケンスに分割する。例えば、読み出し−変更−書き込み命令は、
>  読み出し−変更命令 + ストア命令に分割すると、高速化が可能である。この手法を利
>  用すれば、新しいコードシーケンスが元のコードシーケンスより大きくなった場合で
>  も、パフォーマンスが向上する。
らしいのでADD m64,r64みたいな命令はパフォーマンス上のデメリットがあるから使用を控えた方が良さそう
0853デフォルトの名無しさん
垢版 |
2020/08/29(土) 02:13:33.36ID:kcJTulzj
x64命令の動作を確認するのに対話式にアセンブル&実行&レジスタの確認が出来るツールとかないかな?
各値を変えながら試行錯誤したいけどソース書いてアセンブルしてデバッガに読み込んでステップ実行してだと手間すぎる

今MULのフラグの更新動作がAMDの資料を見てもIntelの資料を見てもググってももよく判らない
0854デフォルトの名無しさん
垢版 |
2020/08/29(土) 17:42:02.36ID:CDQjtNyx
>>853
フラグ類は、言葉で説明が難しいので、擬似コードで説明されている Intel の資料が
どこかにあるはず。
0855デフォルトの名無しさん
垢版 |
2020/08/29(土) 18:05:14.09ID:CDQjtNyx
>>853
Intel® 64 and IA-32 Architectures
Software Developer’s Manual
Volume 2A:
Instruction Set Reference, A-M

-------------------------------------------------
[MUL—Unsigned Multiply]
・・・
Flags Affected
The OF and CF flags are set to 0 if the upper half of the result is 0; otherwise, they
are set to 1. The SF, ZF, AF, and PF flags are undefined.
0856デフォルトの名無しさん
垢版 |
2020/08/29(土) 18:39:05.44ID:kcJTulzj
>>855
その文章は確認していてAMD64のドキュメントにも
>If the upper half of the product is non-zero, the instruction sets the carry flag (CF) and overflow flag
>(OF) both to 1. Otherwise, it clears CF and OF to 0.
と似たような記述があるんだけど双方の資料に書いてある"upper half"がどの部分を示しているのか判らない
演算結果の上半分が入るDレジスタの事?
0857デフォルトの名無しさん
垢版 |
2020/08/29(土) 19:05:00.05ID:CGaweZC2
>>856
Intelの日本語マニュアルには処理の疑似コードが載ってる。
これによると、上半分というのは、各命令で使うレジスタサイズの上半分とわかる。
8,16,32bitそれぞれ場合によって上半分の長さが変わるのでそう書くしかない。
だから64bitの場合の上半分は上位32bitになる。

操作
IF (NumberOfOperands = 1)
 THEN IF (OperandSize = 8)
  THEN
   AX ← AL ? SRC (* signed multiplication *)
   IF AL = AX
    THEN CF ← 0; OF ← 0;
    ELSE CF ← 1; OF ← 1;
   FI;
  ELSE IF OperandSize = 16
   THEN
    DX:AX ← AX ? SRC (* signed multiplication *)
    IF sign_extend_to_32 (AX) = DX:AX
     THEN CF ← 0; OF ← 0;
     ELSE CF ← 1; OF ← 1;
    FI;
   ELSE (* OperandSize = 32 *)
    EDX:EAX ← EAX ? SRC (* signed multiplication *)
    IF EAX = EDX:EAX
     THEN CF ← 0; OF ← 0;
     ELSE CF ← 1; OF ← 1;
  FI;
FI;
0858デフォルトの名無しさん
垢版 |
2020/08/29(土) 19:47:52.94ID:cC8g9MrB
upper half of the product だから乗算結果の上半分だ。
疑問の余地は無いと思うがな…
0860デフォルトの名無しさん
垢版 |
2020/08/30(日) 01:05:43.21ID:BjChy3oe
IF sign_extend_to_32 (AX) = DX:AX
 THEN CF ← 0; OF ← 0;
 ELSE CF ← 1; OF ← 1;
FI;

これだと符号拡張したものと比較しているから、言葉による説明と違っている。
基本的に、mulは、符号無しの整数に対する掛け算なのだが。
0861デフォルトの名無しさん
垢版 |
2020/08/30(日) 01:11:49.03ID:BjChy3oe
>>857
それは、mul(符号無し掛け算)ではなく、imul(符号付掛け算)の擬似コードで、
英語版でも、同じような擬似コードが書いてあり、言葉による説明は、
次のようになっている:
Flags Affected
For the one operand form of the instruction, the CF and OF flags are set when signif-
icant bits are carried into the upper half of the result and cleared when the result fits
exactly in the lower half of the result. For the two- and three-operand forms of the
instruction, the CF and OF flags are set when the result must be truncated to fit in the
destination operand size and cleared when the result fits exactly in the destination
operand size. The SF, ZF, AF, and PF flags are undefined.
0862デフォルトの名無しさん
垢版 |
2020/08/30(日) 01:22:29.16ID:BjChy3oe
ちなみに、同じビット数の2つの整数の掛け算は、結果の内、掛ける前の整数の
ビット数の部分に限定した部分だけを見れば、符号付き掛け算と符号無し掛け算
で結果が変わらない。
一方、imulは、2オペランド以上のものは、結果のビット数が、掛ける前と同じ。
そして、mulは、2オペランド以上のものが用意されて無い。
これは、最初に述べた性質から、imulとmulで、2オペランド以上の場合では、
結果が変わらなくなってしまうため、imulだけで、符号無し掛け算にも対応できる
ためである。
0864デフォルトの名無しさん
垢版 |
2020/08/30(日) 14:26:36.90ID:EVylyaDc
>>863
昔は大学教授しかこういう講義してなかったが、今は若い女の子が講義してくれるのかw
いい時代になったな
0866デフォルトの名無しさん
垢版 |
2020/08/31(月) 15:24:59.40ID:r6h0vUdb
セクションとかも理解してくれるx64逆アセンブラとかないのかな
セクション情報やデバッグ情報をディレクティブ等でコードと一緒に出力してくれるとうれしい
0870デフォルトの名無しさん
垢版 |
2020/09/03(木) 14:20:08.59ID:cueCbpYZ
>>869
秋月に女の子が部品買いに来てるのなんて見たことないんだが、時代はそこまで来てるのか?
女の子がハンダごて握ってなんか作ってる姿は萌えるかも知れない
0871デフォルトの名無しさん
垢版 |
2020/09/04(金) 10:09:14.61ID:KmpQA39o
>>870
今時ネット通販だろうけど本屋と同じで
たまたま近くに置いてあるのに目が止まるのが良かったりするんだけどな
パートおばさんのハンダ付け作業なんて若年化する前にほぼ中国海外にいったろう
最近は新入社員研修に後ろから二人羽織状態で手を握りながら・・
0872デフォルトの名無しさん
垢版 |
2020/09/06(日) 06:21:38.35ID:EKeL4GkH
ドキュメント72時間で秋葉原の部品屋やってたけど
女子高生がオリジナルのペンライトを作るために来てた
0878デフォルトの名無しさん
垢版 |
2020/09/07(月) 22:17:45.58ID:KQEAaFWf
半田ごてを持つ部分が間違ってるし、基盤もハンダ付けする面は上下逆だし、
さあに、こういう基盤は、最近ではかなりの部分がロボットでハンダ付けしてると
聞いている。
0880デフォルトの名無しさん
垢版 |
2020/09/08(火) 03:25:35.85ID:jacy6RM2
何周遅れか判らんくらい激しく概出過ぎてつまらん
0887デフォルトの名無しさん
垢版 |
2020/11/25(水) 09:47:14.54ID:gT5in2ls
好奇心でMS-DOS 6.2にJWasmを入れてアセンブラ入門サイトを見ながら学習しています。
大きな値を10進変換したい場合はどうすれば良いのでしょう?
DX:AX ÷ 10dがしたい。

INT21hファンクションコールでAH=36hを実行してAX * BX * CXした結果を
DIV 10するのに、商が16ビットを超えるので例外が発生する。

入門中なので、2バイトまでの環境しか使い方がわかりません。

4バイトのレジスタが使えれば解決する話なのかも知れませんけど、、
DX:AXから計算する方法ないか調べています。
結局、EDX:EAXを10dで割る事になっても同じことが起きるので
0888デフォルトの名無しさん
垢版 |
2020/11/25(水) 12:44:21.97ID:jzvQX9aE
>>887
(1)まず、DXを10で割る。
その時の商をQ1(ax),余りをR1(dx)とする。
(2)
mov ax,元のAX
xor dx,dx  ;← dx=0
add ax,R1
adc dx,0
とする。これは、元のAXにR1を足したものを(dx:ax)に入れていることに相当する。
(3)
(dx:ax)を10で割り、商をQ2(ax)、余りをR2(dx)とする。
(4) 最終的な商Qは、(Q1:Q2), 余りRは、R2である。
0889デフォルトの名無しさん
垢版 |
2020/11/25(水) 12:46:48.67ID:jzvQX9aE
>>888
すまん。ちょっと間違った。(2)は正しくは、
(2)
mov ax,元のAX
とする。
これは、これは、(dx:ax)=(R1:元のAX)に相当する。

だった。
0890デフォルトの名無しさん
垢版 |
2020/11/25(水) 12:50:41.35ID:jzvQX9aE
コードに直すとこうなると思う。

;入力: (dx:ax)
;出力: (Q1:ax)=商, 余り=dx

mov original_ax,ax
mov ax,dx
xor dx,dx
mov cx,10
div cx
mov Q1,ax
mov ax,original_ax
div cx
;商=(Q1:ax), 余り=dx
ret
0891デフォルトの名無しさん
垢版 |
2020/11/25(水) 13:07:31.94ID:jzvQX9aE
>>887
32BIT(4バイト)命令を使っていいなら、(dx:ax)/10 は、
shl edx,16
mov dx,ax
mov eax,edx
xor edx,edx
mov ecx,10
idiv ecx
で、eax に32BITの商、edx に余り(0〜9)が出る。
0894デフォルトの名無しさん
垢版 |
2020/11/25(水) 14:55:43.27ID:gT5in2ls
MUL BX
MUL CX
MOV Q2, DX
MOV Q1, AX
MOV BX, 10
DIV_LOOP:
XOR DX, DX
MOV AX, Q2
DIV BX
MOV Q2, AX
MOV AX, Q1
DIV BX
MOV Q1, AX
ADD DX, '0'
PUSH DX
OR AX, AX
JNZ DIV_LOOP

こんな感じですか?
気になったのですが、MOV DX, 0ではなくて、XOR DX, DXなのは処理が速いから?
CMP AX, 0よりも、OR AX, AXの方が良いのでしょうか?
0896デフォルトの名無しさん
垢版 |
2020/11/25(水) 16:46:45.83ID:jzvQX9aE
>>894
>気になったのですが、MOV DX, 0ではなくて、XOR DX, DXなのは処理が速いから?
>CMP AX, 0よりも、OR AX, AXの方が良いのでしょうか?
昔は速かったので今でも伝統的に0を代入する変わりにxor reg,regを
使い、cmp ax,0の変わりに or ax,axを使う人が多い。
しかし、その「昔」とは、80486とかよりもずっと昔の初代8086の時代のことかもしれない。
ただし、xor reg,regだとフラグ類まで初期化されてしまうので、mov reg,0を使った方が
良い場合がある。

>>895
今は速くは無いが、昔は速かった。
その伝統が何故か今でも継承されている。
0897デフォルトの名無しさん
垢版 |
2020/11/25(水) 16:58:10.99ID:jzvQX9aE
>>894
冒頭の
MUL BX
MUL CX
の部分が怪しい。一行目で結果がDX:AXに入っているのに、二行目ではそれを
無視しているが、無視してはいけない。

また、最後の
OR AX, AX
JNZ DIV_LOOP
の判定は間違い。
これだと、Q2がまだ非0の場合にもループが終わってしまう。
ちゃんと、Q2が非0の場合もループを続行しなくてはならない。

また、Qは、商(quotient)の頭文字を使っただけで、伝統的には、
意味が余り分からない変数は、work1 などを使う慣例があったりする。
意味が分かる場合には、意味が分かるような変数名にする。
0898デフォルトの名無しさん
垢版 |
2020/11/25(水) 17:02:18.40ID:jzvQX9aE
なお、Q1は、説明の都合上、数学と似た感覚で短い変数を付けたが、
アセンブラなどに書く場合には、もっと長い名前にした方がいい。
短いとアセンブラが何かと混同して問題になるかも知れないから。
例えば、レジスタ名にr1などというものがある場合があるので注意。
0901デフォルトの名無しさん
垢版 |
2020/11/26(木) 01:11:06.89ID:lH6B10sG
>>899
では、現在のIntelCPUにおいて、
・mov reg,0の代わりにxor reg,reg
・cmp eax,0の変わりにor eax,eax
を使うメリットをそれぞれ書いてみてください。
0902デフォルトの名無しさん
垢版 |
2020/11/26(木) 12:23:04.16ID:kAbnbrOP
# mk_src.rb
def mk_src( md, loop1 = 1000000, loop2 = 1000 )
tit, fpath, asm_str = case md
when 1; [ 'imd', 'imd.c', %Q{\t\tasm( "movl $0, %eax\\ncmpl $0, %eax" );\n} ]
when 2; [ 'reg', 'reg.c', %Q{\t\tasm( "xorl %eax, %eax\\norl %eax, %eax" );\n} ]
end
File.open( fpath, 'w:UTF-8' ){|fh|
fh.print <<_EOT_
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

int main(void)
{
LARGE_INTEGER qpff, qpf0, qpf1;
QueryPerformanceFrequency( &qpff );

unsigned int n = #{loop2};
QueryPerformanceCounter( &qpf0 );
while( n-- ){
#{asm_str * loop1}
}
QueryPerformanceCounter( &qpf1 );
printf( " #{tit}. time %lf[ms]\\n", (double)(qpf1.QuadPart - qpf0.QuadPart) * 1000.0 / qpff.QuadPart );
return 0;
}
_EOT_
} # File.open
end

mk_src( 1 )
mk_src( 2 )
0903デフォルトの名無しさん
垢版 |
2020/11/26(木) 12:23:28.07ID:kAbnbrOP
$ uname -srvmo
MINGW64_NT-10.0-18363 3.1.7-340.x86_64 2020-09-22 20:54 UTC x86_64 Msys

$ gcc imd.c -O0 -o imd; gcc reg.c -O0 -o reg
8291652 imd.exe
6291780 reg.exe

$ ./imd.exe; ./imd.exe; ./imd.exe; ./imd.exe
imd. time 221.844800[ms]
imd. time 236.904100[ms]
imd. time 205.867200[ms]
imd. time 242.199800[ms]

$ ./reg.exe; ./reg.exe; ./reg.exe; ./reg.exe
reg. time 134.806000[ms]
reg. time 145.542900[ms]
reg. time 147.039100[ms]
reg. time 143.031100[ms]
0904デフォルトの名無しさん
垢版 |
2020/11/26(木) 12:58:51.67ID:lH6B10sG
Intelの最適化マニュアルを見たが、or,xor,cmp,movのlatencyやthroughputは
CPUによりマチマチで、絶対にどれが速いと言うようなことはいえないと思う。
ややこしいのは、movは、latencyが1や0.5, throughoutが0.5なのに対し、
xorは、latencyが1, throughtputが0.33や0.5となっていたりする。
これもCPUIDによってさまざま。
表の中のCPUIDの表記法も独特なので、どれが最新のCPUに対応しているのかも
個人的には今のところ分からない。
0905デフォルトの名無しさん
垢版 |
2020/11/26(木) 13:10:05.83ID:Ndl69lfH
>>904
常に最新の情報を見て一番いいものを使うのが正しいよね。
伝統とか言ってるようじゃダメ。頭が腐る。
0906デフォルトの名無しさん
垢版 |
2020/11/26(木) 14:55:11.18ID:l8W6EZba
馬鹿ほど脳みそ足りないからAppleのようにすぐ互換性を捨てたがる。
そんな馬鹿は伝統を重んじてきたx86系を使わないでほしい。
0907デフォルトの名無しさん
垢版 |
2020/11/26(木) 16:30:36.87ID:s+oX3EtE
>>896
不具合なければどっちでもよくね?
どっちかにしなければいけないほど古いPCを今でも使っている人?
0908デフォルトの名無しさん
垢版 |
2020/11/26(木) 18:31:44.20ID:b0/J9kY8
命令自体のクロック数は多少違うかもしれんがキャッシュ効率も考えれば1バイト命令のxor ax,axの方が正解の確率が高いと思うよ。
0910デフォルトの名無しさん
垢版 |
2020/11/26(木) 18:48:11.36ID:HK02mgb4
x86は386,486,586,686と拡張されてきて、その度に命令が拡張されてきてる。これらはどれもx86だが、
これらの互換性を取ろうとすると386に合わせるしかなくなる。しかしそれでは今のWindowsは動かない。
一般の人にとって互換性というのは普段使っているアプリケーションが動けばいいので、それでほぼ支障ない。

最近のIntel CPUはHaswell、Broadwell、Skylake、Kebylakeと来ているが、これらの間だけ見ても
命令が拡張されているので完全な互換性はない。ならば互換性を重視して、最新CPUの便利な機能を使うな
ということになると技術者のレベルは昔のまま上がらないことになる。それは時代に取り残されることにならないか。

386はシングルコアだったが今はマルチコアが当たり前の時代だ。しかしソフトウェアは今でもシングルコアを
前提に書くことが多い。その方が簡単だしそれでも動くからだ。しかし、搭載されているコア数を最初に見て、
マルチコアだったら並列処理できるところは並列で動かせば早くなるのがわかっていても。互換性のために
わざとそうしないとしたらそれはただの怠慢に過ぎないだろう。そういう人はx86系を使わないでほしい。
0911デフォルトの名無しさん
垢版 |
2020/11/26(木) 18:55:48.10ID:l8W6EZba
このように互換性捨てろという奴は頭悪いとよく分かる。
PowerPC、IA64、MIPSから何も学んでないのだ。
0914デフォルトの名無しさん
垢版 |
2020/11/26(木) 19:52:22.98ID:lH6B10sG
>>909
今見てみたら、xor reg,reg や sub reg,reg には「実行依存性」を断ち切る効果が
あると書いてあった。Pentium 4 から特別な扱いをする様になったとか。
つまり、xor reg,regだとフラグまで初期化してしまうので、フラグが決まるまで
Latencyを待つ必要が無い。
ところが、mov reg,0だとフラグは引き継ぐから前の命令によってフラグが
決まるまで次の命令の実行が待たされることがあるのかな。
もしかしたら、CPU内部では、ZF,CF,SFなどと独立して変更できずに、
EFLAGS全体を1つのレジスタの様に扱うことが基本になっていて、
一部だけを変更しようとすると待機が発生しやすくなるのかもしれない。
0915デフォルトの名無しさん
垢版 |
2020/11/26(木) 19:56:51.64ID:lH6B10sG
>>914
スマン。
そういう意味ではないようだわ。
or eax,ebx
とかだと、直前までの命令でeaxとebxの両方のレジスタの値が決まってないと
パイプライン上でこの命令ALUのステージを実行することは出来ないので待機が
発生する。
ところが、xor eax,eax だと直前までの命令のeaxの結果がどうであれ、この
命令は必ずeaxを0にしてしまうから、待機する必要が無い、という意味だった。
0916デフォルトの名無しさん
垢版 |
2020/11/26(木) 20:18:29.14ID:l8W6EZba
コード長はくだらん揚げ足取りに見える。普通にオペランドも入れて解釈すべきでキャッシュ効率は不利。
昔からレジスタ初期化で多用されるxorは組み合わせ回路、ワイヤードロジック一発で多くのCPUでも特別扱い。

XOR r32, r32 L: 0.07ns= 0.2c T: 0.07ns= 0.24c
OR r32, r32 L: 0.29ns= 1.0c T: 0.07ns= 0.25c
AND r32, r32 L: 0.29ns= 1.0c T: 0.10ns= 0.33c
0917デフォルトの名無しさん
垢版 |
2020/11/26(木) 20:42:01.46ID:l8W6EZba
よく使う命令を重点的にトランジスタを大量投入して速くしようというのはコードの互換性を大事にしてるからの発想。古いコードでも速く動かしてやるという努力の賜物のx86。
一方、使わない命令は削除、もう頭使うのが嫌だからと最適化はコンパイラの仕事と最適化を放り出して衰退したRISC哲学。
0918デフォルトの名無しさん
垢版 |
2020/11/26(木) 20:43:40.28ID:lH6B10sG
>>916
mov reg,0
は、オペランドも全て含めて2バイト。
0は、short formで8BITオペランドになるから。
xor reg,regは、immオペランドが無くても2バイト。
なぜなら、movは、特別な短いマシン語が割り当てられているのに、xorは
そうではないから。
0919デフォルトの名無しさん
垢版 |
2020/11/26(木) 20:50:33.32ID:weG7Hi1V
タブ機能付きのソフト(AcrobatReaderとかテキストエディターとか)の現在アクティブな
タブのファイルパスのアドレスを調べたいんですけど、めちゃめちゃ頑張ったんですけど無理でした。
わかったことは、AcrobatReaderの場合、開いた順にインデックスが振られて(初めの値は0
ではなく1)、アクティブタブのインデックスが格納されたアドレスがあるということです。
もしくはインデックスが振られるのではなく、ファイルパスを開いた順に配列にプッシュして
ファイルパス配列[アクティブタブのインデックス - 1] のタブをアクティブにしろという命令が出てる。
前者の場合、インデックスが格納されてるアドレスがどこかさっぱりわかんなくって、ファイルパス
のアドレスからちょっと前をみたりマックスパスの260Byte後ろのとこを見たりしたんですけど
それらしきインデックスが見つかりませぬ。
それで、ファイルパスにアクセスしてる関数を見たんですけどアセンブリ言語サッパリ( 一一)
どなたか助言お願いします。

ファイルパスにアクセスしてるらしき関数↓
AcroRd32.dll+4637E - 33 D2 - xor edx,edx
AcroRd32.dll+46380 - 8B C1 - mov eax,ecx
AcroRd32.dll+46382 - 66 39 11 - cmp [ecx],dx
AcroRd32.dll+46385 - 74 08 - je AcroRd32.dll+4638F
AcroRd32.dll+46387 - 83 C0 02 - add eax,02 { 2 }
AcroRd32.dll+4638A - 66 39 10 - cmp [eax],dx
AcroRd32.dll+4638D - 75 F8 - jne AcroRd32.dll+46387
AcroRd32.dll+4638F - 2B C1 - sub eax,ecx
AcroRd32.dll+46391 - D1 F8 - sar eax,1
AcroRd32.dll+46393 - 5D - pop ebp
AcroRd32.dll+46394 - C3 - ret

もう1週間くらい頑張ってます。宜しくお願いします。
0920デフォルトの名無しさん
垢版 |
2020/11/27(金) 00:50:22.02ID:dazyxaWu
>>918
ならないな。バイナリ出して。

0100 mov ax,0
0103 xor ax,ax
0100 B8 00 00 31 C0

B8 00 00 00 00 mov eax,0
33 C0 xor eax,eax
0922デフォルトの名無しさん
垢版 |
2020/11/27(金) 14:37:53.57ID:35rurNSb
>>919
何をしたいのかが分からないが、例えばVS2019にAcrobatReaderの*.exeファイルを
ドラッグアンドドロップして、デバッグを開始し、タブにファイルを開いた状態にする。
そこでデバッガによりアプリを停止させて、メモリー内でそのファイル名を検索する。
どうやって検索すればよいかは良く知らない。
VS2019ではなく、OllyDbgなどを使えばよいかもしれない。
それでファイル名が入っているメモリーアドレスは分かることは分かる。
もう一つは、ファイルをオープンする場合、必ず Win32 の CreateFile APIが呼び出される
ので、CreateFileの 関数アドレスにブレイクポイントを仕掛ける。
その状態で実行すると何回かブレイクしているうち、タブのファイル名に対して
CreateFileが呼び出されることがあるはず。
その状態になったら、コールスタック(呼び出し履歴)を辿って、CreateFileを
呼び出している場所を見つける。そうすると、ファイル名を渡しているコードが
見つかる。
0923デフォルトの名無しさん
垢版 |
2020/11/27(金) 14:42:33.59ID:35rurNSb
>>922
なお、ファイルパスの入っているアドレスは分かる様になるが、
当然、アドレスは毎回変化するので、果たして何をしたいか、ということになる。
ファイルパスを入れているメモリーブロックを malloc や new している
コードを探すことは出来るかもしれないし、そのアドレスをどこかに格納している
コードも探すことは可能かも知れない。
が、複雑すぎて、そこで得た知見で何かをするということは
アセンブラに最高に詳しい人でもかなり難しい。
0924デフォルトの名無しさん
垢版 |
2020/11/27(金) 14:47:20.40ID:35rurNSb
>>923
例えば、OllyDbgなどを使えば、ファイルパスが入っているメモリーアドレスを
検索して探し出すことは出来るかも知れない。
それで見つかったアドレスを X とする。
今度は、そのアドレス X を格納しているメモリーを探すこともできることはできる
可能性がある。
その場合、little endian なので、バイトレベルでは下位バイトから上位バイトに
向かって格納されていることに注意する。
ただし、アドレスXが格納されているアドレスは、複数見つかる可能性がある。
また、X そのものではなく、X より少し小さいアドレスが格納されていることもありえる。
だから、このような解析は難しいものとなる。

またこのような方法以外に、dumpbin に /disasm オプションをつけて Acrobat の *.exeを
逆アセンブルした結果を併用するのが基本。
0925デフォルトの名無しさん
垢版 |
2020/11/27(金) 14:53:31.46ID:35rurNSb
>>924
そのような方法で粘り強く解析していくと、dumpbinの逆アセンブルコードの
どのあたりで、ファイルパスを格納するメモリーを確保し、そのアドレスを
どこかに記録しているコードは見つかる可能性は有る。
ただし、問題はそう簡単ではなく、「どこかに記録している」の「どこか」
がまた、毎回アドレスが変わることにある。
C/C++で言えば、非常に多数の構造体が連鎖的にリンクされているから。
このくらいの規模のアプリだと、その連鎖は、10以上になることは少なくない。
連鎖の仕方もif分などで場合分けされていて、条件によって複雑に代わりうる。
ソースコードがあっても複雑すぎてなにをやっているかを理解することはとても
困難。だから、ソースコードが無い状態でそれを理解することはとてつもなく
難しい。
0929デフォルトの名無しさん
垢版 |
2020/11/28(土) 00:34:33.70ID:qjEapHwo
> mov reg,0
> は、オペランドも全て含めて2バイト。
> 0は、short formで8BITオペランドになるから。

これって本当なの? そうアセンブルされないけど。
0930デフォルトの名無しさん
垢版 |
2020/11/28(土) 17:46:27.32ID:WIRcuTWz
>>929
どのCPUかによって変わるだろ。
自分が使ってるCPUのマニュアルを読んで自分で確認したらどうか。
0931デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:17:09.98ID:qjEapHwo
アスペなの? ボクのCPUの話じゃなく、
本人はz80ではなくx86だと言ってるからx86の話を聞いているんだよ。
他社の互換含めてx86系CPUが一体どれだけあると思ってるの? 全部確認できるわけないじゃん。
0932デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:21:31.70ID:kjtXSxRe
>>919
です!!>>922 さんありがとうございました!
なんとアクティブタブのファイルパスアドレス見つかりました!
AHKですけど、よかったら皆さんこの関数使ってください!

;==================================================
JEE_GetAcroRd32Path(hWnd)
{
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "AcrobatSDIWindow")
return
WinGet, vPID, PID, % "ahk_id " hWnd
WinGet, vPPath, ProcessPath, % "ahk_id " hWnd
FileGetVersion, vPVersion, % vPPath

MAX_PATH := 260
;PROCESS_QUERY_INFORMATION := 0x400 ;PROCESS_VM_READ := 0x10
if !hProc := DllCall("kernel32\OpenProcess", UInt,0x410, Int,0, UInt,vPID, Ptr)
return
if !vAddress && A_Is64bitOS
{
DllCall("kernel32\IsWow64Process", Ptr,hProc, IntP,vIsWow64Process)
vPIs64 := !vIsWow64Process
}
0933デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:22:46.29ID:Sl4N7Gov
AMD64やIA-32eのマニュアルに2バイトで0クリア出来るオペコードはないように見えるな
0934デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:23:26.87ID:kjtXSxRe
if !vAddress
{
VarSetCapacity(MEMORY_BASIC_INFORMATION, A_PtrSize=8?48:28, 0)
vAddress := 0
Loop
{
if !DllCall("kernel32\VirtualQueryEx", Ptr,hProc, Ptr,vAddress, Ptr,&MEMORY_BASIC_INFORMATION, UPtr,A_PtrSize=8?48:28, UPtr)
break

vMbiBaseAddress := NumGet(MEMORY_BASIC_INFORMATION, 0, "Ptr")
vMbiRegionSize := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?24:12, "UPtr")
vMbiState := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?32:16, "UInt")
;vMbiProtect := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?36:20, "UInt")
vMbiType := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?40:24, "UInt")

vName := ""
if (vMbiState & 0x1000) ;MEM_COMMIT := 0x1000
&& (vMbiType & 0x1000000) ;MEM_IMAGE := 0x1000000
;&& (vMbiProtect = 0x4) ;PAGE_READWRITE := 0x4
{
vPath := ""
VarSetCapacity(vPath, MAX_PATH*2)
DllCall("psapi\GetMappedFileName", Ptr,hProc, Ptr,vMbiBaseAddress, Str,vPath, UInt,MAX_PATH*2, UInt)
if !(vPath = "")
SplitPath, vPath, vName

}
0935デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:25:32.47ID:kjtXSxRe
if InStr(vName, "AcroRd32.dll")
{
;get address where path starts
;if vPIs64{
; vAddress := vMbiBaseAddress + 0x19d3d9c
;}
;else{
vAddress := vMbiBaseAddress + 0x19d3d9c
;}
break
}
vAddress += vMbiRegionSize
if 0
if (vAddress > 2**32-1) ;4 gigabytes
{
DllCall("kernel32\CloseHandle", Ptr,hProc)
return
}
}
}
0936デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:26:33.51ID:kjtXSxRe
VarSetCapacity(MEMORY_BASIC_INFORMATION, A_PtrSize=8?48:28, 0)
if vAddress
&& DllCall("kernel32\VirtualQueryEx", Ptr,hProc, Ptr,vMbiBaseAddress, Ptr,&MEMORY_BASIC_INFORMATION, UPtr,A_PtrSize=8?48:28, UPtr)
{
memVal := ReadMemory32(vAddress, 0, vPID)
memVal := ReadMemory32(memVal, 0x78, vPID)
memVal := ReadMemory32(memVal, 0x18, vPID)
memVal := ReadMemory32(memVal, 0x10, vPID)
memVal := ReadMemory32(memVal, 0x10, vPID)
;memVal += 0x0
vPath := ""
VarSetCapacity(vPath, MAX_PATH*2)
DllCall("psapi\GetMappedFileName", Ptr,hProc, Ptr,vMbiBaseAddress, Str,vPath, UInt,MAX_PATH*2, UInt)
if InStr(vPath, "AcroRd32.dll")
{
vPath2 := ""
VarSetCapacity(vPath2, MAX_PATH*2, 0)
DllCall("ReadProcessMemory", "UInt", hProc, UInt, memVal, Str, vPath2, Uint, MAX_PATH*2, UPtr,0)
vPath3 := StrGet(&vPath2, "cp932")
}
}
DllCall("kernel32\CloseHandle", Ptr, hProc)
return vPath3
}
0937デフォルトの名無しさん
垢版 |
2020/11/28(土) 20:28:28.40ID:kjtXSxRe
ReadMemory32(MADDRESS, pOffset = 0, activePID := 0)
{
VarSetCapacity(MVALUE,8)
ProcessHandle := DllCall("OpenProcess", "Int", 24, "Char", 0, "UInt", activePID, "UInt")
lastErr := DllCall("GetLastError")
DllCall("ReadProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS+pOffset, "Str", MVALUE, "Uint",8, "Uint *",0)
DllCall("CloseHandle", "int", ProcessHandle)
result := 0
Loop 4{
result += *(&MVALUE + A_Index-1) << 8*(A_Index-1)
}
return result
}
0940デフォルトの名無しさん
垢版 |
2020/11/29(日) 15:27:25.94ID:g07v1NN9
>>938
手書きですよ〜〜。自動生成とかどうやってやるんですか?ぼくにはそんな
AIみたいなプログラム作れません。
0942デフォルトの名無しさん
垢版 |
2020/11/29(日) 15:50:37.08ID:sV/hNKwx
x86で該当しそうなのはmovzx movsxくらいだけどな。
movzx ax,0
でオペランド含めて
OF B6 00
の3バイト。
xor ax,axが1バイトというのはオペランドを含まないならそうかもしれんな。
mov ax,0がオペランド込みで2バイトのコードがあるなら教えてほしい。
0943デフォルトの名無しさん
垢版 |
2020/11/29(日) 16:30:48.26ID:tmDS9Mir
>>942
8BIT測値を16/32BITに拡張する「即値拡張」なる形式が、add,sub,or,xor,and
adc,sbb,cmp や、push,imul には存在しているが、mov命令には存在してないようだ。
0944デフォルトの名無しさん
垢版 |
2020/11/29(日) 19:36:03.18ID:g07v1NN9
>>941
AcrobatReaderのウィンドウハンドルを渡して、アクティブタブのファイルパス
が返ってくる関数ですよー。

F1::
;F1を押したら
;アクティブウィンドウハンドルの取得(AcrobatReaderをアクティブにしといてください)
hwnd := WinExist("A")
;アクティブタブのファイルパスを取得
filePath := JEE_GetAcroRd32Path(hwnd)
;メッセージボックスで表示
MsgBox, % filePath
return

こんな感じで使ってください。
0952デフォルトの名無しさん
垢版 |
2020/12/01(火) 20:53:32.04ID:QGlkeoFk
人がいないスレをわざわざ上げる必要ないので
関係ない話なら他の上がっているスレに書けばいいだろ
0955デフォルトの名無しさん
垢版 |
2020/12/13(日) 02:46:51.94ID:46vi4xSP
素朴な思い付きの疑問なのだけど、どうして書籍としてAMD64の入門書が無いの?
需要も知識ある人も、それなりに居そうだけど。

まさか、AMDから許可がおりないとか?
0959955
垢版 |
2020/12/14(月) 05:46:00.53ID:lPWXZq4e
>>958
店頭在庫を見て歩いて早幾年、無いと思っていたけれどあるのね。
しかし多様性はなさそう。

情報ありがとう。
0962デフォルトの名無しさん
垢版 |
2020/12/14(月) 17:48:08.53ID:yiGrKys0
>>960
プログラミングの本じゃない。プログラミングの前にx64のアーキテクチャを知らないと話にならないだろ。
それを知るための本。
0963デフォルトの名無しさん
垢版 |
2020/12/15(火) 23:33:29.39ID:JKngFzP4
64bitアセンブラの本もあるじゃないか
「64ビットアセンブラ入門―64ビットCPUの基本構造もやさしく解説」 (Amazon)
0964デフォルトの名無しさん
垢版 |
2020/12/16(水) 08:28:24.95ID:4AurUS4h
アセンブラは、C のポインタで躓かないように
Z80 程度を少し (もちろんポインタを使う程度) やればいいと思う。
0966デフォルトの名無しさん
垢版 |
2020/12/16(水) 19:53:44.68ID:xpVb4SZu
>>965
各種レジスタ構成やそれらの性質、仮想記憶のしくみなどを知らずにアセンブラやろうとするのは無謀もいいとこだろう。
Cで書いたコードの一部をアセンブラに書き換えて変更したり最適化するとき、Cのコードに対応するアセンブラソースが
どうなっているか見るにはCで何をしようとしているかわからないと話にならないだろう。
こういうことは知ってて損することはない。
0967デフォルトの名無しさん
垢版 |
2020/12/19(土) 08:32:12.96ID:SL5FUo+H
>>963
その本、Cから呼び出す前提だったから、アセンブラでの変数宣言の仕方は載ってない。
0969デフォルトの名無しさん
垢版 |
2020/12/19(土) 20:11:53.26ID:TfP5rB1Q
CD21 を学習しないとなw
0971デフォルトの名無しさん
垢版 |
2020/12/20(日) 04:41:50.25ID:mOcnJILL
>>970
Cコンパイラが生成したアセンブラよく読んだよ
0972デフォルトの名無しさん
垢版 |
2020/12/20(日) 12:47:01.51ID:NmAfNXJq
>>967
int some_data = 5;
という変数は、アセンブラでは以下のようにすると定義できる:
_DATA segment DWORD
_some_data dd 5
_DATA ends

dd は、define dword の意味。db だと byte, dw だと word、となる。
構造体の場合は、struc を使うか、または、メンバのdd,dw,dbをそのまま並べる。
自動 align はされないので、alignment をとりたい場合は、自分で pading するか、
align 擬似命令か、even 擬似命令を使う。
0973デフォルトの名無しさん
垢版 |
2020/12/20(日) 12:48:36.41ID:NmAfNXJq
_DATA segment DWORD
の部分の DWORD は、そのセグメントの先頭を、DWORD でアラインする、という
意味。つまり、セグメントの先頭アドレスが 4 の倍数に配置される。
省略も可能。
アラインメントをしなくてもプログラムは動くが、少し遅くなることが有る。
0974デフォルトの名無しさん
垢版 |
2020/12/21(月) 08:58:26.80ID:LKkS73pR
>>973
いやいや、bus errorでしょもう。
0975デフォルトの名無しさん
垢版 |
2020/12/21(月) 11:00:51.03ID:i3HSzHFO
今時のISAはアライメントズレでロード/ストアした場合でも遅くなるだけじゃね
IA32、AMD64、ARM、RX、RISC-V
あたりはアライメントがずれていても例外は吐かないように見える
0976デフォルトの名無しさん
垢版 |
2020/12/21(月) 13:34:54.19ID:xeeueWnS
>>974
x86, AMD64 だと 読み書きが遅くなるだけで bus error にはならない。
但し、スタックポインタの値は 4 または 8 の倍数になっていないと
例外が起きる仕組みがある。
0977デフォルトの名無しさん
垢版 |
2020/12/21(月) 13:38:38.63ID:xeeueWnS
構造体メンバのアラインメントも、x86, AMD64 では速度面以外では必要ではない。
他の系統のCPUでは、アラインメントが揃ってないと読み込めない様になっている
ことがあるが、x86, AMD64 の人から見ると、そういったCPUに足をひきづられて
ウザイことがある。
そういうCPUのために、x86, x64 では不要の構造体のアラインメントなどウルサすぎる。
0978デフォルトの名無しさん
垢版 |
2020/12/21(月) 14:24:05.05ID:xeeueWnS
構造体メンバのアラインは、x86、x64でも速度のために有ったほうが良いかも
知れないが、バイナリファイルの中の32BIT整数の部分をアラインするのは、
ちょっと抵抗を感じることがある。
ファイルの場合、読み込み速度よりサイズの小ささが重要だと思うので。
他のCPUでは読み込めないなら、そのCPUの設計が欠陥だとも考えられるし、
そんなCPUの事まで配慮してサイズが増大するのはいい迷惑。
0979デフォルトの名無しさん
垢版 |
2020/12/21(月) 17:07:46.38ID:GZaqA6YK
バイナリファイル解析してるとアライン考慮部分と全く配慮してないが混在されてるのがまれによくある
0980デフォルトの名無しさん
垢版 |
2020/12/21(月) 19:28:27.84ID:LKkS73pR
アライメントなんかアセンブルディレクティブ疑似命令で自動でやってくれるでしょ.sizeofとかもアライメント考慮してサイズ返してくれるし。
コンパイラが再生するデータ構造はアライメント合わせされてる。x86でオプティマイズサイズだとされないか。
0981デフォルトの名無しさん
垢版 |
2020/12/21(月) 20:01:53.70ID:Ttyv2kNo
高性能PC!!
を謳ってる配信でintelが全く見当たらなくなったのは隔世の感があるな。
配信してる超絶プログラマさんももうAMDしか選択肢がない言うてた
0996デフォルトの名無しさん
垢版 |
2021/01/03(日) 18:36:17.00ID:GJkrCLRp
        まもなくここは 乂1000取り合戦場乂 となります。

      \∧_ヘ     / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
 ,,、,、,,, / \〇ノゝ∩ < 1000取り合戦、いくぞゴルァ!!       ,,、,、,,,
    /三√ ゚Д゚) /   \____________  ,,、,、,,,
     /三/| ゚U゚|\      ,,、,、,,,                       ,,、,、,,,
 ,,、,、,,, U (:::::::::::)  ,,、,、,,,         \オーーーーーーーッ!!/
      //三/|三|\     ∧_∧∧_∧ ∧_∧∧_∧∧_∧∧_∧
      ∪  ∪       (    )    (     )   (    )    )
 ,,、,、,,,       ,,、,、,,,  ∧_∧∧_∧∧_∧ ∧_∧∧_∧∧_∧∧_∧
      ,,、,、,,,       (    )    (    )    (    )    (    )
10011001
垢版 |
Over 1000Thread
このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 1361日 23時間 35分 51秒
10021002
垢版 |
Over 1000Thread
5ちゃんねるの運営はプレミアム会員の皆さまに支えられています。
運営にご協力お願いいたします。


───────────────────
《プレミアム会員の主な特典》
★ 5ちゃんねる専用ブラウザからの広告除去
★ 5ちゃんねるの過去ログを取得
★ 書き込み規制の緩和
───────────────────

会員登録には個人情報は一切必要ありません。
月300円から匿名でご購入いただけます。

▼ プレミアム会員登録はこちら ▼
https://premium.5ch.net/

▼ 浪人ログインはこちら ▼
https://login.5ch.net/login.php
レス数が1000を超えています。これ以上書き込みはできません。