X



アセンブラ初心者スレッド 2©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
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でも配列へのアクセスはインデックスレジスタ付きなのは変わらなかった。

このサンプルでは配列の添え字がコンパイル時に推定できないようにしたのでインデックスレジスタ付きになってるけど、
普通のループでは、この部分は最適化されてポインタに変更されて、レジスタ間接とポインタ操作するコードになるはず。
■ このスレッドは過去ログ倉庫に格納されています

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