初心者OK!質問大歓迎!のアセンブラのスレッドです。
基本情報の勉強中の人、PICやH8を勉強中の学生などなど…
前スレ
アセンブラ初心者スレッド
http://echo.2ch.net/test/read.cgi/tech/1314502612/
関連スレ
アセンブラ 13
http://echo.2ch.net/test/read.cgi/tech/1314512680/
探検
アセンブラ初心者スレッド 2©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
2017/04/13(木) 17:35:55.70ID:1WMn3pSz
2018/06/13(水) 17:23:26.62ID:5n7sRExk
edas86覚えてる人いる?
60デフォルトの名無しさん
2018/07/04(水) 22:19:45.76ID:gFgZc5FG TDC
2018/07/05(木) 16:39:14.28ID:AeL6VB/V
TDC
2018/07/21(土) 07:03:04.58ID:HztBSU4B
オブジェクト指向のアセンブラアプリのお薦めを教えてください。
63デフォルトの名無しさん
2018/07/21(土) 10:03:59.76ID:JzufiDOi Julia
2018/07/31(火) 18:07:47.27ID:K5ZjI7P1
初心者なので意味が解らないんだけど、オブジェクト指向って考え方なんじゃないの?
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
とするのかな。
分けて入れる場合、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
とするのかな。
2018/07/31(火) 23:38:20.35ID:M9aZq/V8
あ、訂正させて。
多分、正しくは:
shl rax,32
shld rdx,rax,32
mov rbx,rbx
多分、正しくは:
shl rax,32
shld rdx,rax,32
mov rbx,rbx
2018/07/31(火) 23:39:52.06ID:M9aZq/V8
もしかして、mmx レジスタや xmm レジスタの、shuffle 命令なども使えたりする
のだろうか??
のだろうか??
2018/07/31(火) 23:44:49.05ID:M9aZq/V8
すまん。最訂正。
shl rax,32
shld rdx,rax,32
mov rbx,rdx
shl rax,32
shld rdx,rax,32
mov rbx,rdx
69デフォルトの名無しさん
2018/07/31(火) 23:51:35.80ID:PrQlt9wc >>68
もちつけ
もちつけ
2018/07/31(火) 23:53:48.39ID:Yh1Yhi2x
shl rdx, 16
mov ebx, eax
or rbx, rdx
mov ebx, eax
or rbx, rdx
2018/07/31(火) 23:55:11.65ID:Yh1Yhi2x
16じゃなくて32
2018/07/31(火) 23:58:34.01ID:M9aZq/V8
なるほど、つまり:
shl rdx, 32
mov ebx, eax
or rbx, rdx
と。OR を使うとは全く思いつかなかった。
shl rdx, 32
mov ebx, eax
or rbx, rdx
と。OR を使うとは全く思いつかなかった。
2018/08/01(水) 00:00:05.11ID:M1fpQAcB
考えてみれば、C言語ではいつも、シフトとOR使ってやってた・・・。
74デフォルトの名無しさん
2018/08/01(水) 00:02:01.85ID:s+zy6Um6 もちつけ
75デフォルトの名無しさん
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
などとする必要がある。
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
などとする必要がある。
2018/08/01(水) 00:48:03.95ID:hfBYO5dB
64bitレジスタの上位が0になるのは無駄な依存関係を無くすため
32bitレジスタの部分書き換えは大きなペナルティが発生するので注意
32bitレジスタの部分書き換えは大きなペナルティが発生するので注意
2018/08/01(水) 00:52:48.93ID:hfBYO5dB
アセンブラで高速なコードを書くなら
インテルの最適化マニュアルを一通り読むことを勧める
IACAも非常に便利
インテルの最適化マニュアルを一通り読むことを勧める
IACAも非常に便利
2018/08/01(水) 20:01:51.01ID:UPXl5ngF
アセンブラは普通に書いただけでもCに比べてバイナリも非常に小さいし高速に動いてくれるよね
2018/08/01(水) 23:09:30.00ID:iFKJPY0w
ペナルティを避けるため、普通は同じレジスタでも別のでもいいから、movzx使って上位ビットが0だって明示してから使うべき
2018/08/01(水) 23:17:32.46ID:iFKJPY0w
今回の64ビットバージョンのrbx <--- edx:eax としたい場合は関係なかったけど、
mov bx,dxをやった後にebxやrbxを参照するとペナルティが発生するのは32ビットでも一緒だけどね
mov bx,dxをやった後にebxやrbxを参照するとペナルティが発生するのは32ビットでも一緒だけどね
2018/08/02(木) 20:11:37.64ID:Hff70ZxX
2018/08/02(木) 20:19:01.70ID:1EegAYN5
それ
2018/08/02(木) 21:46:38.87ID:Hff70ZxX
IACAってなんかすごい
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数の変更はされない、というのが素直な解釈だったから。
確か、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数の変更はされない、というのが素直な解釈だったから。
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
.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
2018/08/11(土) 19:55:58.66ID:Pi7uIeu1
エラーでは、my_title になってるけど、5ch に登校する際に、
ソースを my_mojiretu に変えただけなので、同じと思って。
あと、somothing は、something の typo。
ソースを my_mojiretu に変えただけなので、同じと思って。
あと、somothing は、something の typo。
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 を超えるような値になった場合にはどうしようも
ないと。
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 を超えるような値になった場合にはどうしようも
ないと。
2018/08/11(土) 20:08:54.58ID:XlVyBwpc
ちょっと勉強になった
64bitでasm触ることなくなったもんなー
64bitでasm触ることなくなったもんなー
2018/08/11(土) 22:13:23.67ID:QecvtyFY
2018/08/12(日) 06:39:04.85ID:kb51JNcZ
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を超えた固定アドレスのメモリをアクセスできないというわけではない。
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を超えた固定アドレスのメモリをアクセスできないというわけではない。
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 の限界を特に気にすることは無い。
.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 の限界を特に気にすることは無い。
2018/08/12(日) 07:04:02.85ID:kb51JNcZ
>>92
間違った。 ebx ではなく、rbx だった:
lea rbx,ラベル名 ;2
lea rbx,[disp32]
lea rbx,[rip + rel_addr32]
間違った。 ebx ではなく、rbx だった:
lea rbx,ラベル名 ;2
lea rbx,[disp32]
lea rbx,[rip + rel_addr32]
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 バイトにアラインされた状態になってくれる。
だから、余り難しい事を考える必要は無い。
実は、以下のようにしておくだけで、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 バイトにアラインされた状態になってくれる。
だから、余り難しい事を考える必要は無い。
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 のように書く必要性は、近年では下がっているようだから。
固定しなくては、構造化例外を処理出来なくなる。
なので、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 のように書く必要性は、近年では下がっているようだから。
2018/08/16(木) 13:27:50.54ID:ZqqdGQwm
>>95
誤:esp, ebp
正:rsp, rbp
【なぜ、3の必要性が少ないかについて】
3のようにしなくても、そもそも、3の第二オペランドの値は、メモリ上において
あるのだから、レジスタが不足しても値が消えてしまう事はない。だから、
保存の必要も無い。
レジスタが不足した場合に保存する必要があるのは、必ずレジスタの値。
だから、mov [rsp + disp], reg の形式で十分保存できてしまう。
誤:esp, ebp
正:rsp, rbp
【なぜ、3の必要性が少ないかについて】
3のようにしなくても、そもそも、3の第二オペランドの値は、メモリ上において
あるのだから、レジスタが不足しても値が消えてしまう事はない。だから、
保存の必要も無い。
レジスタが不足した場合に保存する必要があるのは、必ずレジスタの値。
だから、mov [rsp + disp], reg の形式で十分保存できてしまう。
2018/08/16(木) 15:37:56.45ID:y9SUHRBN
2018/08/16(木) 21:00:56.95ID:aOzS/OcU
内部的にロード、ストアは別命令
アセンブラの命令数とかあまり関係ない
アセンブラの命令数とかあまり関係ない
2018/08/18(土) 06:32:40.93ID:v9RxAPQU
100デフォルトの名無しさん
2018/08/18(土) 06:35:45.68ID:v9RxAPQU push、popはコードサイズに制限のある、プロローグ、エピローグ部分で使うことはあるけど、
あまり必要性はなくなったよ。
あまり必要性はなくなったよ。
101デフォルトの名無しさん
2018/08/18(土) 07:05:31.99ID:v9RxAPQU push、popみたいに複数のμOPになる命令は利用可能なデコーダーも制限されるので
他の命令のデコードも阻害しやすい。
演算命令のメモリオペランドみたいに、フュージョンされて簡単デコーダーで発行できるようになったのもあるけど。
他の命令のデコードも阻害しやすい。
演算命令のメモリオペランドみたいに、フュージョンされて簡単デコーダーで発行できるようになったのもあるけど。
102デフォルトの名無しさん
2018/08/18(土) 08:53:46.48ID:LWSvYoUk103デフォルトの名無しさん
2018/08/18(土) 09:10:13.08ID:LWSvYoUk104デフォルトの名無しさん
2018/08/18(土) 14:23:17.32ID:LlnBri0A >>103
それ、可能と言えば可能だけど、64bit化のメリットのかなりの部分が消えてしまうし、
DLLでも制限なく使えるんだっけ?
と思って調べたらやっぱ問題あるよなあ。
https://www.webtech.co.jp/blog/optpix_labs/programing/6387/
それ、可能と言えば可能だけど、64bit化のメリットのかなりの部分が消えてしまうし、
DLLでも制限なく使えるんだっけ?
と思って調べたらやっぱ問題あるよなあ。
https://www.webtech.co.jp/blog/optpix_labs/programing/6387/
105デフォルトの名無しさん
2018/08/18(土) 19:54:44.26ID:D84MOd5V >>103
mov cl, hogehoge
これでアセンブルして、dumpbin /relocations test01.obj
これで見ると
hogehogeがREL32になる(PC相対の32bitオフセット)
ラベルの種類としてRIP相対のREL32はあるけど
通常のレジスタに32bit相対のラベルの種類がないのでは?
だからエラーになると
mov cl, hogehoge
これでアセンブルして、dumpbin /relocations test01.obj
これで見ると
hogehogeがREL32になる(PC相対の32bitオフセット)
ラベルの種類としてRIP相対のREL32はあるけど
通常のレジスタに32bit相対のラベルの種類がないのでは?
だからエラーになると
106デフォルトの名無しさん
2018/08/18(土) 21:13:26.29ID:D84MOd5V 簡単なWindowsのアプリを作ってWinMainのアドレスを表示すると
0x000000003fdf1770
俺の環境ではこんな値が出た
これってアドレスとしては1GBくらいの位置
下位32bitの絶対アドレスで指定すると符号付と解釈した場合に
残り1GBの範囲しかアクセスできない
だから、64bitのWindowsや/3GBスイッチを指定した32bitWindowsでは
下位32bitの絶対アドレスで指定するなとマイクロソフトは決めたのでは?
RIP相対なら開始アドレスに関係なくRIPの相対値なので
プログラムがロードされた位置に関わらず2GBまでアクセスできる
0x000000003fdf1770
俺の環境ではこんな値が出た
これってアドレスとしては1GBくらいの位置
下位32bitの絶対アドレスで指定すると符号付と解釈した場合に
残り1GBの範囲しかアクセスできない
だから、64bitのWindowsや/3GBスイッチを指定した32bitWindowsでは
下位32bitの絶対アドレスで指定するなとマイクロソフトは決めたのでは?
RIP相対なら開始アドレスに関係なくRIPの相対値なので
プログラムがロードされた位置に関わらず2GBまでアクセスできる
107デフォルトの名無しさん
2018/08/18(土) 21:29:59.45ID:D84MOd5V 同じようなプログラムを32bitで作ってコンパイルしたらWinMainの開始アドレスは
0x013215a0
アドレスとしては19MBくらいの位置
64bitアプリは32bitアプリよりもずっと高位のアドレスにロードされるんだろうね
だから64bitアプリでは下位32bitでの絶対アドレス指定は禁止してるのかも
0x013215a0
アドレスとしては19MBくらいの位置
64bitアプリは32bitアプリよりもずっと高位のアドレスにロードされるんだろうね
だから64bitアプリでは下位32bitでの絶対アドレス指定は禁止してるのかも
108デフォルトの名無しさん
2018/08/19(日) 12:41:20.07ID:plhuPGbS 論理的に高位か下位かはどうでもよくね?
109デフォルトの名無しさん
2018/08/19(日) 16:59:22.46ID:XvleiWNb110デフォルトの名無しさん
2018/08/19(日) 17:05:58.03ID:XvleiWNb だからこそ
>>85の
mov al,my_mojiretu[rbx] ;3
のようなコードを書くとリンカがエラーを吐くようになってるんだろうね
下位32bitの絶対アドレスで指定するなと
>>85の
mov al,my_mojiretu[rbx] ;3
のようなコードを書くとリンカがエラーを吐くようになってるんだろうね
下位32bitの絶対アドレスで指定するなと
111デフォルトの名無しさん
2018/08/19(日) 17:21:35.92ID:XvleiWNb ほとんどのCPUでは64bitのアドレスを直接指定する方法は限定されてて、実行速度も遅くなる
だからWindowsやLinuxでは64bitでもデフォルトではスタティックに割り当てられたシンボルは
だいたい32bitの値として扱ってる
(Linuxではコンパイラのオプションでメモリモデルを指定できて
スタティックなシンボルを64bitの値として扱うこともできる)
64bit Windowsの場合、かなり高位のアドレスにロードされるようだから
RIP相対の32bitの値として扱ってるのだろう
ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
だからWindowsやLinuxでは64bitでもデフォルトではスタティックに割り当てられたシンボルは
だいたい32bitの値として扱ってる
(Linuxではコンパイラのオプションでメモリモデルを指定できて
スタティックなシンボルを64bitの値として扱うこともできる)
64bit Windowsの場合、かなり高位のアドレスにロードされるようだから
RIP相対の32bitの値として扱ってるのだろう
ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
112デフォルトの名無しさん
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は絶対アドレス値を足してるので)
adrp x0, :pg_hi21:hogehoge
add x0, x0, :lo12:hogehoge
これで読み込む
これで33bitのページ単位でPC相対のアドレスを読み込める
つまり64bitのARMではスタティックなシンボル値は33bitのPC相対アドレスとして扱ってる
(相対なのはページ単位なので下位12bitは動かせない、下位12bitは絶対アドレス値を足してるので)
113デフォルトの名無しさん
2018/08/19(日) 17:34:00.29ID:XvleiWNb 64bitのARMのadrp命令と同等の命令はRISC-Vや最近発表されたnanoMIPSなどでも採用されてる
RISC-VやnanoMIPSは33bitではなく32bitだが
RISC-VやnanoMIPSは33bitではなく32bitだが
114デフォルトの名無しさん
2018/08/19(日) 17:41:09.62ID:XvleiWNb スタティックなシンボル値の制約はアセンブラではなくあくまでコンパイラの仕様だが
(コンパイラ側でシンボルを扱う場合にあえて下位32bitしか読み込まない仕様にしてる)
最近のアセンブラプログラミングでは高級言語とリンクすることが多いので必須な知識
(コンパイラ側でシンボルを扱う場合にあえて下位32bitしか読み込まない仕様にしてる)
最近のアセンブラプログラミングでは高級言語とリンクすることが多いので必須な知識
115デフォルトの名無しさん
2018/08/19(日) 19:20:24.59ID:r48xSuow >>111
> ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
> 64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
> ほとんどのCPUでは64bitのアドレスを直接指定する方法は限定されてて、実行速度も遅くなる
つまりこういうこと?
・動的に割り当てられたデータは64bitでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitでアクセスするように制限されてるけど実行速度は速い。
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
> ちなみにこれはスタティックに割り当てられたデータだけで動的に割り当てられたデータは
> 64bitのポインタ値で扱われるのでユーザプログラムが扱える全仮想メモリ領域に配置できる
> ほとんどのCPUでは64bitのアドレスを直接指定する方法は限定されてて、実行速度も遅くなる
つまりこういうこと?
・動的に割り当てられたデータは64bitでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitでアクセスするように制限されてるけど実行速度は速い。
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
116デフォルトの名無しさん
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()のラベルを指定)
>・動的に割り当てられたデータは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()のラベルを指定)
117デフォルトの名無しさん
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)
不正解
lui a0, a0, data01
addi a0, a0, data01
ld a0, (a0)
正解
lui a0, %hi(data01)
addi a0, a0, %lo(data01)
ld a0, (a0)
118デフォルトの名無しさん
2018/08/20(月) 06:10:04.15ID:yBkytAxc >>116
アドレッシングの話をしているだと思ったのではしょったけどこう書けばいいですかね
・動的に割り当てられたデータは64bitアドレッシングでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されてるけど実行速度は速い
・どちらの場合も読み書きできるデータサイズに制限はない
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
アドレッシングの話をしているだと思ったのではしょったけどこう書けばいいですかね
・動的に割り当てられたデータは64bitアドレッシングでアクセスできるけど実行速度が遅くなる
・静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されてるけど実行速度は速い
・どちらの場合も読み書きできるデータサイズに制限はない
・ただしLinuxの場合、メモリモデルを指定して再コンパイルすればこの制限はなくなる
119デフォルトの名無しさん
2018/08/20(月) 07:34:26.88ID:VWtXo5Rn 何で、動的に割り当てられた変数と静的に割り当てられた変数の
アクセス速度を比較するのか意味不明だが
一番アクセスが速いのはローカル変数だと思うぞ
ローカル変数はdisplacement付きのスタックポインタ間接アドレッシングでアクセスできるので
ほとんどのCPUでdisplacementが届く範囲なら1命令でロード、ストアができるからね
アクセス速度を比較するのか意味不明だが
一番アクセスが速いのはローカル変数だと思うぞ
ローカル変数はdisplacement付きのスタックポインタ間接アドレッシングでアクセスできるので
ほとんどのCPUでdisplacementが届く範囲なら1命令でロード、ストアができるからね
120デフォルトの名無しさん
2018/08/21(火) 13:09:22.87ID:rmPseMne >>119
今までの話の流れで言うと、速度を比較するのが目的ではなくて、
なぜ静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されているのか?
ですよ。普通に考えたら64bitアドレッシングが制限なくできて当たり前だろ。なんで?ってことです。
今までの話の流れで言うと、速度を比較するのが目的ではなくて、
なぜ静的に割り当てられたデータは32bitアドレッシングでアクセスするように制限されているのか?
ですよ。普通に考えたら64bitアドレッシングが制限なくできて当たり前だろ。なんで?ってことです。
121デフォルトの名無しさん
2018/08/21(火) 13:14:13.58ID:EQ4qcC3V x86の64bitモードでのアドレッシングは全て64bit
122デフォルトの名無しさん
2018/08/21(火) 16:35:27.52ID:R5Y2p11o123デフォルトの名無しさん
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
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
124デフォルトの名無しさん
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
という命令が、 専用命令として特別扱いとして存在しているが、特殊中の特殊。
確か、そのリンカオプションは、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
という命令が、 専用命令として特別扱いとして存在しているが、特殊中の特殊。
125デフォルトの名無しさん
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 は、「マクロアセンブラ」であって、通常のアセンブラとは結構異なるので。
訂正:
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 は、「マクロアセンブラ」であって、通常のアセンブラとは結構異なるので。
126デフォルトの名無しさん
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
みたいな感覚。みたいなだけで、実際にはそのまま書くと、エラーになる
かも知れない。
誤: 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
みたいな感覚。みたいなだけで、実際にはそのまま書くと、エラーになる
かも知れない。
127デフォルトの名無しさん
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 = 構造体の先頭アドレス
のような場合。
さらに補足すると、
mov cl, [rbx + disp32]
の disp32 は、rbx の中身によって意味が変わってきて、
1. disp = 32BIT 相対アドレス (rbx が絶対アドレスの場合)
2. disp = 32BIT 絶対アドレス (rbx が相対アドレスの場合)
となる。2. の例としては、
rbx = 配列添え字 * (配列の要素のバイト数)
のような場合。1. の例としては、
rbx = 構造体の先頭アドレス
のような場合。
128デフォルトの名無しさん
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絶対アドレスでは届かない位置にロードされる可能性があるからだろうな
今やってみたが
64bitアプリを通常にコンパイルした場合のWinMainのアドレス
0x000000013f291770
/largeaddressaware:noを付けてコンパイルした場合のWinMainのアドレス
0x0000000001241770
/largeaddressaware:noを付けるとプログラムがロードされるアドレスが変わる
64bitのアプリを通常にコンパイルするとWinMainのアドレスが0x000000013f291770
およそ先頭から5GBの位置
つまり、32bit絶対アドレスでは届かない位置にプログラムがロードされてる
/largeaddressaware:noをつけると先頭から18MBくらいの位置
エラーが出るのは32bit絶対アドレスでは届かない位置にロードされる可能性があるからだろうな
129デフォルトの名無しさん
2018/08/22(水) 04:40:24.11ID:8qwUBnhH 補足:
/largeaddressaware:noを付けると64bitアプリでもメモリは2GBまでしか使えなくなる
/largeaddressaware:noを付けると64bitアプリでもメモリは2GBまでしか使えなくなる
130デフォルトの名無しさん
2018/08/22(水) 04:46:45.21ID:8qwUBnhH つまり、>>128が示してることは
Windowsの64bitアプリでは
mov al,my_mojiretu[rbx]
のような書き方はしてはいけないということ
Windowsの64bitアプリでは
mov al,my_mojiretu[rbx]
のような書き方はしてはいけないということ
131デフォルトの名無しさん
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]
>のような書き方はしてはいけないということ
今までなんで絶対アドレスが出てくるのか疑問だったけど、コンパイラはこういうコードは吐かない、ってことだよね。
/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]
>のような書き方はしてはいけないということ
今までなんで絶対アドレスが出てくるのか疑問だったけど、コンパイラはこういうコードは吐かない、ってことだよね。
132デフォルトの名無しさん
2018/08/22(水) 19:32:17.75ID:J61dDDqI133デフォルトの名無しさん
2018/08/22(水) 19:39:47.75ID:J61dDDqI >>130
でも現実は、複雑。
なぜなら、COFFの仕様的には、obj ではない Image(EXEやDLLの事) のためだけに
ある .reloc section には、64BIT 絶対アドレスの再配置も行えるようになっているから。
現状の MS 製の link.exe がどうなっているかはともかく。
でも現実は、複雑。
なぜなら、COFFの仕様的には、obj ではない Image(EXEやDLLの事) のためだけに
ある .reloc section には、64BIT 絶対アドレスの再配置も行えるようになっているから。
現状の MS 製の link.exe がどうなっているかはともかく。
134デフォルトの名無しさん
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 絶対アドレスに対応していても、無理だった。
勘違いした。
すまん。間違った。
mov al,my_mojiretu[rbx]
は、意味的には、
mov al, [rbx + offset my_mojiretu]
となって、最後は、
mov al, [rbx + disp32]
となるが、disp32 の部分は、disp64 の命令は存在していないので、
.reloc section が 64BIT 絶対アドレスに対応していても、無理だった。
勘違いした。
135デフォルトの名無しさん
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 位の値だった。
一応、論理的には、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 位の値だった。
136デフォルトの名無しさん
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.
正しくは、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.
137デフォルトの名無しさん
2018/08/22(水) 20:11:19.88ID:J61dDDqI >>128
自分の勘だと、そのアドレスは、WinMain よりも、DLL の DllMain が置かれるような
値になってるね。
不思議だ。WinMain をそんな大きなアドレスに置く必要性は余り無いハズなので。
初期化データが 2GB 未満に置かれていても、malloc() や、new で確保されるデータは、
64BIT アドレスにできるはずだし。なお、
1_3f29_1770
↑は、32BIT を超えて、33BIT の値だな・・・。なんちゅう大きな値だろう。
自分の勘だと、そのアドレスは、WinMain よりも、DLL の DllMain が置かれるような
値になってるね。
不思議だ。WinMain をそんな大きなアドレスに置く必要性は余り無いハズなので。
初期化データが 2GB 未満に置かれていても、malloc() や、new で確保されるデータは、
64BIT アドレスにできるはずだし。なお、
1_3f29_1770
↑は、32BIT を超えて、33BIT の値だな・・・。なんちゅう大きな値だろう。
138デフォルトの名無しさん
2018/08/22(水) 20:46:10.32ID:dx23aElG 64bitもアドレス空間があるんだから
多少大きくても何の問題も無いだろ
多少大きくても何の問題も無いだろ
139デフォルトの名無しさん
2018/08/22(水) 21:22:24.95ID:WDZbf6Te >>134
32bitのフラットメモリモデルだと、静的変数はイメージにはオフセットを入れといて、
実行時にローダで書き換えてたんだと思うんだけど、64bitでは絶対アドレスは制約が大きくなるから変だと思ったんだ。
絶対アドレスはコンパイラでも使えなくはないけど、デバイスドライバでメモリマップトI/O操作するような時しか使わないと思う。
64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
mov al,my_mojiretu[rbx]
みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?
32bitのフラットメモリモデルだと、静的変数はイメージにはオフセットを入れといて、
実行時にローダで書き換えてたんだと思うんだけど、64bitでは絶対アドレスは制約が大きくなるから変だと思ったんだ。
絶対アドレスはコンパイラでも使えなくはないけど、デバイスドライバでメモリマップトI/O操作するような時しか使わないと思う。
64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
mov al,my_mojiretu[rbx]
みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?
140デフォルトの名無しさん
2018/08/22(水) 21:24:18.64ID:WDZbf6Te 例外吐くことで
141デフォルトの名無しさん
2018/08/23(木) 05:44:12.90ID:sOVf8lyT >>135
コマンドライン用の簡単なC言語の64bitのプログラムで試したが
main関数のアドレス=0x000000013f7f1000
data sectionで定義した変数data01のアドレス=0x000000013f7fc087
だったぞ
完全に32bit絶対アドレスの範囲を超えてる
コマンドライン用の簡単なC言語の64bitのプログラムで試したが
main関数のアドレス=0x000000013f7f1000
data sectionで定義した変数data01のアドレス=0x000000013f7fc087
だったぞ
完全に32bit絶対アドレスの範囲を超えてる
142デフォルトの名無しさん
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
WinMain address = 0x000000013fd419a0
data sectionの変数のアドレス
data01 address = 0x000000013fd4d000
/largeaddressaware:noを付けた場合
WinMain address = 0x00000000013619a0
data sectionの変数のアドレス
data01 address = 0x000000000136d000
143デフォルトの名無しさん
2018/08/23(木) 07:09:02.23ID:4LRopBJn >>139
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
>mov al,my_mojiretu[rbx]
>みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?
意味不明だ。別に、
mov al,my_mojiretu[rbx]
というコードが悪いわけではない。
むしろ、最適化のためには使った方が効率が良くなる。
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
>mov al,my_mojiretu[rbx]
>みたいなコードが例外吐いて特定困難なバグが発生するのを防止してるのでは?
意味不明だ。別に、
mov al,my_mojiretu[rbx]
というコードが悪いわけではない。
むしろ、最適化のためには使った方が効率が良くなる。
144デフォルトの名無しさん
2018/08/23(木) 07:22:22.74ID:4LRopBJn >>141-142
もしそうだとすると、VC++ の吐くコードがx64の命令を上手く使いきれてないという事になる。
本来であれば、アドレスの配置を上手く行うだけで、64BIT モードでも特に問題なく
mov al,my_mojiretu[rbx]
という命令は使えて、かつ、64BIT アドレスの制限を受けるわけでもないのだから。
ちなみに、アプリの EXE は、リンク後は固定アドレスで、ローダーがアドレスを再配置
する事はない。だから、ImageBase を小さい値になるようにリンクしさえすれば、
問題が生じない。
もしそうだとすると、VC++ の吐くコードがx64の命令を上手く使いきれてないという事になる。
本来であれば、アドレスの配置を上手く行うだけで、64BIT モードでも特に問題なく
mov al,my_mojiretu[rbx]
という命令は使えて、かつ、64BIT アドレスの制限を受けるわけでもないのだから。
ちなみに、アプリの EXE は、リンク後は固定アドレスで、ローダーがアドレスを再配置
する事はない。だから、ImageBase を小さい値になるようにリンクしさえすれば、
問題が生じない。
145デフォルトの名無しさん
2018/08/23(木) 07:27:31.64ID:4LRopBJn >>139
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
通常、コンピュータソフト、特にOSのセキュリティーというのは、そういう人間的なもの
ではなくて、もっと厳密な物だ。
ランダマイズして撹乱して相手の目をくらます、などという方法は通常取られない。
実際、EXE ファイルを解析した経験からしても、ランダマイズなどは全く行われていない。
何回リンクしても、同じアセンブリソースや、同じC++ソースなら、全く同じアドレスになる。
異なるソースであっても、ベースアドレスなどは、ほとんどの場合、固定値。
>64bitでイメージベースが大きくなったのは、セキュリティ関係でランダマイズしたりとか、
通常、コンピュータソフト、特にOSのセキュリティーというのは、そういう人間的なもの
ではなくて、もっと厳密な物だ。
ランダマイズして撹乱して相手の目をくらます、などという方法は通常取られない。
実際、EXE ファイルを解析した経験からしても、ランダマイズなどは全く行われていない。
何回リンクしても、同じアセンブリソースや、同じC++ソースなら、全く同じアドレスになる。
異なるソースであっても、ベースアドレスなどは、ほとんどの場合、固定値。
146デフォルトの名無しさん
2018/08/23(木) 07:58:52.05ID:4LRopBJn >>138
実際には問題がある。なぜなら、そんなにアドレスが大きいと、さっきから話題の
mov al, my_mojiretu[rbx]
という命令が使えなくなるからだ。
これは、グローバルな配列変数を、添え字でアクセスするような場合に良いコードに
なる事がある。僅かではあるが。もし、この命令が使えないとなると、
mov rdx,offset my_mojiretu
mov al,[rdx + rbx]
のように、2つの命令を使わなくてはならなくなり、最適化上、不利になる。
実際には問題がある。なぜなら、そんなにアドレスが大きいと、さっきから話題の
mov al, my_mojiretu[rbx]
という命令が使えなくなるからだ。
これは、グローバルな配列変数を、添え字でアクセスするような場合に良いコードに
なる事がある。僅かではあるが。もし、この命令が使えないとなると、
mov rdx,offset my_mojiretu
mov al,[rdx + rbx]
のように、2つの命令を使わなくてはならなくなり、最適化上、不利になる。
147デフォルトの名無しさん
2018/08/23(木) 08:10:29.27ID:wxGNRrqx そんな事言い出したら
4GBや64KBに限定した方が小さいコードになるから
compactモデルにしよう
とかいう話にもなる
昔に戻りたい?
何のための64bit?
4GBや64KBに限定した方が小さいコードになるから
compactモデルにしよう
とかいう話にもなる
昔に戻りたい?
何のための64bit?
148デフォルトの名無しさん
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 などにも
全て影響する貴重な間接オペランド。
だから、そういうことじゃなく、EXEファイルの中に、2GBを越える初期化データを
誰が入れたいかって話なんだ。
別に、ImageBase を小さい値にしていても、malloc() や、new するデータは、
6GBでも理論上は確保できるわけで、制限されるのは、EXEファイルの中の
初期化データのサイズが2GBまで、ってだけなんだ。
それで、使えるマシン語の間接オペランドの種類が1つ増やせる。
mov 命令だけでなく、add, sub, mul, div, idiv, lea, addps, addss などにも
全て影響する貴重な間接オペランド。
149デフォルトの名無しさん
2018/08/23(木) 08:46:40.08ID:4LRopBJn >>147
8086時代の 64KB では制限が大きすぎて、ほとんどのプログラムで、制限が足かせ
になっていたので、32BIT になって、アドレスが 4GB に拡張されて非常に便利になった。
ところが、64BIT 時代になっても、そのときのようなメリットが無いと思うんだ。
AMD vs Intel の競争の結果出てきた産物かも知れない。そういうの、時々ある。
8086時代の 64KB では制限が大きすぎて、ほとんどのプログラムで、制限が足かせ
になっていたので、32BIT になって、アドレスが 4GB に拡張されて非常に便利になった。
ところが、64BIT 時代になっても、そのときのようなメリットが無いと思うんだ。
AMD vs Intel の競争の結果出てきた産物かも知れない。そういうの、時々ある。
150デフォルトの名無しさん
2018/08/23(木) 08:56:25.66ID:K9a3gVgQ >>145
WindowsではASLRでランダム化普通にやってるらしいですよ
http://07c00.hatenablog.com/entry/2013/08/07/033443
OSがプロセスをロードするときに、ランダムな場所にモジュールを配置するセキュリティ機能です。
実際はモジュールだけじゃなく、スタックやヒープなどもランダマイズされたりします。
WindowsではASLRでランダム化普通にやってるらしいですよ
http://07c00.hatenablog.com/entry/2013/08/07/033443
OSがプロセスをロードするときに、ランダムな場所にモジュールを配置するセキュリティ機能です。
実際はモジュールだけじゃなく、スタックやヒープなどもランダマイズされたりします。
151デフォルトの名無しさん
2018/08/23(木) 09:03:22.89ID:4LRopBJn >>150
少なくとも、EXE の .text, .data セクションは再配置される事は無いはず。
なぜなら、.reloc section が存在せず、再配置する事が原理的に出来なくなっているから。
DLL は、.reloc section が残されているので再配置できる。ただし、再配置しなくても、
全てのシステムのDLLは、最初からアドレスが重ならないような ImageBase になっている
ので、再配置されずにそのままおかれるのが、昔は基本であった。
少なくとも、EXE の .text, .data セクションは再配置される事は無いはず。
なぜなら、.reloc section が存在せず、再配置する事が原理的に出来なくなっているから。
DLL は、.reloc section が残されているので再配置できる。ただし、再配置しなくても、
全てのシステムのDLLは、最初からアドレスが重ならないような ImageBase になっている
ので、再配置されずにそのままおかれるのが、昔は基本であった。
152デフォルトの名無しさん
2018/08/23(木) 10:25:25.69ID:3bgfj1QZ153デフォルトの名無しさん
2018/08/23(木) 11:01:43.32ID:4LRopBJn >>152
じゃあなんで、MS純正VSは、いまだに 32BIT コードで動いてるのさ。
x64 は、レジスタが増えた事と、memmove() などが多分、倍の速度で動く事が
最大のメリットじゃないの?
アドレス幅が64BITになって現実的なメリットはどこにあるのかな?
じゃあなんで、MS純正VSは、いまだに 32BIT コードで動いてるのさ。
x64 は、レジスタが増えた事と、memmove() などが多分、倍の速度で動く事が
最大のメリットじゃないの?
アドレス幅が64BITになって現実的なメリットはどこにあるのかな?
154デフォルトの名無しさん
2018/08/23(木) 11:36:32.13ID:3bgfj1QZ なにが「じゃあ」だか
メリットが無いと思うなら2GB限定のアプリにすれば良い
って書いたのが見えなかった?
メリットが無いと思うなら2GB限定のアプリにすれば良い
って書いたのが見えなかった?
155デフォルトの名無しさん
2018/08/23(木) 12:51:14.26ID:4LRopBJn >>154
だから、メリットはあるよ。
レジスタが増えること、AVX, AVX2, AVX512 で、YMM, ZMM レジスタでベクトル
の次元が大きくなったSIMD 命令が使えること、3オペランドの以上のSIMD命令が使える
事、メモリ転送の速度が倍近くになること。malloc(), new が、2GB を超えて行える事。
初期化サイズが2GBを越えるメリットは余り無いと思ってるけど。
だから、メリットはあるよ。
レジスタが増えること、AVX, AVX2, AVX512 で、YMM, ZMM レジスタでベクトル
の次元が大きくなったSIMD 命令が使えること、3オペランドの以上のSIMD命令が使える
事、メモリ転送の速度が倍近くになること。malloc(), new が、2GB を超えて行える事。
初期化サイズが2GBを越えるメリットは余り無いと思ってるけど。
158デフォルトの名無しさん
2018/08/23(木) 18:36:50.55ID:wxGNRrqx >>155
2G限定と関係ないじゃん
2G限定と関係ないじゃん
159デフォルトの名無しさん
2018/08/23(木) 19:03:15.16ID:sOVf8lyT >>148
結局、
mov al,my_mojiretu[rbx]
こんなコードを書くと64bitではLINKする時にエラーが出る
/largeaddressaware:noを指定するとLINKでエラーは出なくなるが、
/largeaddressaware:noを指定すると動的メモリも含め2GB以下のメモリしか扱えなくなる
結局、
mov al,my_mojiretu[rbx]
こんなコードを書くと64bitではLINKする時にエラーが出る
/largeaddressaware:noを指定するとLINKでエラーは出なくなるが、
/largeaddressaware:noを指定すると動的メモリも含め2GB以下のメモリしか扱えなくなる
■ このスレッドは過去ログ倉庫に格納されています
ニュース
- 【日本人の旅行離れ】国内旅行すら行けなくなった……オーバーツーリズムだけじゃない 旅行者減少の異常事態 [ぐれ★]
- 高市首相の答弁書に「台湾有事答えない」と明記 存立危機発言当時 ★12 [蚤の市★]
- 中国の渡航自粛要請1カ月 大阪の観光バス予約ゼロ、東北にも波及 [蚤の市★]
- 【神戸】エレベーター「かご」なく男性医師が転落死 大手「三菱電機ビルソリューションズ」の担当者、安全装置切り放置か [ぐれ★]
- 【福岡】「人が道路に寝込んでいた。顔面から出血し、うなり声をあげている」 福岡市中央区で男性はねられ死亡 タクシー運転手逮捕 [ぐれ★]
- 女性天皇「賛成」69%、将来の皇位継承「不安」68%…読売世論調査 [蚤の市★]
- 高市、メガソーラー廃止。環境破壊が社会問題化 [792147417]
- クリスマスに何かする「予定なし」は54%。 過去最高水準に。ケーキの値上げもあって節約志向へ [663766621]
- 他人のリクエストで自分の癖と異なる絵を上げる絵師いるじゃん?
- なぜ日本人はフード被らないの?寒いのに
- ワイが考えてるキャラ当ててみろやwww
- 🏡おい!返事しろ︎︎!知的障害者!
