質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C

    4528questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • アセンブリ言語

    116questions

    アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

アセンブリ言語で読めない箇所があります。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,771

strike1217

score 568

ポインタを使用するプログラムです。

  1 #include<stdio.h>
  2 #include<ctype.h>
  3 
  4 char *test(char *buf){
  5         char *p;
  6         int c;
  7         p = buf;
  8 
  9         while((c = *p) != 0){
 10                 if(islower(c))
 11                         *p = (char)toupper(c);
 12                 p++;
 13         }
 14         return buf;
 15 }
 16 
 17 int main(){
 18         char s[] = "you will make me happy\n";
 19         printf("%s\n", test(s));
 20 
 21         return 0;
 22 }
 23 


コンパイルしたものを書きます。

    .file    "pointer_arg.c"
    .text
    .globl    test
    .type    test, @function
test:
.LFB2:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movq    %rdi, -24(%rbp)
    movq    -24(%rbp), %rax
    movq    %rax, -8(%rbp)
    jmp    .L2
.L4:
    call    __ctype_b_loc@PLT
    movq    (%rax), %rax
    movl    -12(%rbp), %edx
    movslq    %edx, %rdx
    addq    %rdx, %rdx
    addq    %rdx, %rax
    movzwl    (%rax), %eax
    movzwl    %ax, %eax
    andl    $512, %eax
    testl    %eax, %eax
    je    .L3
    movl    -12(%rbp), %eax
    movl    %eax, %edi
    call    toupper@PLT
    movl    %eax, %edx
    movq    -8(%rbp), %rax
    movb    %dl, (%rax)
.L3:
    addq    $1, -8(%rbp)
.L2:
    movq    -8(%rbp), %rax
    movzbl    (%rax), %eax
    movsbl    %al, %eax
    movl    %eax, -12(%rbp)
    cmpl    $0, -12(%rbp)
    jne    .L4
    movq    -24(%rbp), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size    test, .-test
    .globl    main
    .type    main, @function
main:
.LFB3:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movabsq    $7812735413947559801, %rax
    movq    %rax, -32(%rbp)
    movabsq    $7308533390257515808, %rax
    movq    %rax, -24(%rbp)
    movabsq    $2948273595836448, %rax
    movq    %rax, -16(%rbp)
    leaq    -32(%rbp), %rax
    movq    %rax, %rdi
    call    test
    movq    %rax, %rdi
    call    puts@PLT
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE3:
    .size    main, .-main
    .ident    "GCC: (Debian 6.3.0-18) 6.3.0 20170516"
    .section    .note.GNU-stack,"",@progbits

test()に入ったあとなんですが、、、、
-24(%rbp) = buf
-8(%rbp) = p
-12(%rbp) = c

となっています。(間違っていたらご指摘ください。)

  call    __ctype_b_loc@PLT
    movq    (%rax), %rax
    movl    -12(%rbp), %edx
    movslq    %edx, %rdx
    addq    %rdx, %rdx
    addq    %rdx, %rax
    movzwl    (%rax), %eax
    movzwl    %ax, %eax
    andl    $512, %eax
    testl    %eax, %eax


読めない箇所はここです。

一体何をやっているんでしょうか?
足し算なんてCのプログラム内にはインクリメント以外出てきていません。
なぜ、こんなにadd命令が多いのでしょう?(512なんて知りません。)

__ctype_b_loc@PLTのパラメータはその直前のeaxレジスタ経由でしょうか?
rdiはインクリメントによって変化していないので、eax以外は考えられませんが・・・
PLT経由の関数の呼び出しはシステムコールの時とは違ってパラメータ用のレジスタは決まっていないということですかね・・・・
この関数はislower()に相当するかと思います。

movq    (%rax), %rax
わざわざカッコを付けている理由はなんでしょうか?
() ・・・括弧内のレジスタにアドレスが入っていたら、()はC言語で言う所の間接演算子(*)と同じ効果という理解で正しいでしょうか?
この行はなぜ必要なんですか?

testl    %eax, %eax
同じレジスタのANDを取ってどうするんでしょうか??
意味がよく分かりません。

どなたか教えてください。
Linux 64bit Debianです。

[追記]
私の本のなかでは、islower()の呼び出しは以下のようになっています。
movl -12(%rbp), %eax
movl %eax, %ecx
movq __imp_islower(%rip), %rax
call *(%rax)

call命令の際のレジスタについているアスタリスクはなんのために付いているのでしょうか?
こちらの方が分かりやすいですね。

[追記2]
最適化-O2でやったコードを載せます。

    .file    "pointer_arg.c"
    .text
    .p2align 4,,15
    .globl    test
    .type    test, @function
test:
.LFB15:
    .cfi_startproc
    pushq    %r13
    .cfi_def_cfa_offset 16
    .cfi_offset 13, -16
    pushq    %r12
    .cfi_def_cfa_offset 24
    .cfi_offset 12, -24
    movq    %rdi, %r13
    pushq    %rbp
    .cfi_def_cfa_offset 32
    .cfi_offset 6, -32
    pushq    %rbx
    .cfi_def_cfa_offset 40
    .cfi_offset 3, -40
    subq    $8, %rsp
    .cfi_def_cfa_offset 48
    movsbq    (%rdi), %rbx
    testb    %bl, %bl
    je    .L10
    call    __ctype_b_loc@PLT
    movq    %r13, %rbp
    movq    %rax, %r12
    .p2align 4,,10
    .p2align 3
.L4:
    movq    (%r12), %rax
    testb    $2, 1(%rax,%rbx,2)
    je    .L3
    call    __ctype_toupper_loc@PLT
    movq    (%rax), %rax
    movl    (%rax,%rbx,4), %eax
    movb    %al, 0(%rbp)
.L3:
    addq    $1, %rbp
    movsbq    0(%rbp), %rbx
    testb    %bl, %bl
    jne    .L4
.L10:
    addq    $8, %rsp
    .cfi_def_cfa_offset 40
    movq    %r13, %rax
    popq    %rbx
    .cfi_def_cfa_offset 32
    popq    %rbp
    .cfi_def_cfa_offset 24
    popq    %r12
    .cfi_def_cfa_offset 16
    popq    %r13
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE15:
    .size    test, .-test
    .section    .text.startup,"ax",@progbits
    .p2align 4,,15
    .globl    main
    .type    main, @function
main:
.LFB16:
    .cfi_startproc
    subq    $40, %rsp
    .cfi_def_cfa_offset 48
    movabsq    $7812735413947559801, %rax
    movq    %rax, (%rsp)
    movabsq    $7308533390257515808, %rax
    movq    %rsp, %rdi
    movq    %rax, 8(%rsp)
    movabsq    $2948273595836448, %rax
    movq    %rax, 16(%rsp)
    call    test
    movq    %rax, %rdi
    call    puts@PLT
    xorl    %eax, %eax
    addq    $40, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE16:
    .size    main, .-main
    .ident    "GCC: (Debian 6.3.0-18) 6.3.0 20170516"
    .section    .note.GNU-stack,"",@progbits
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

アセンブルしたものを書きます。

それ、まだアセンブルしていないから笑。コンパイル(してアセンブリコードを生成)しただけです。
俺にもわからない事だらけのアセンブリコードだけど、大まかな想像はつきます。

この関数はislower()に相当するかと

そう、この問題は islower() だ。では islower() って、何だ?

足し算なんてCのプログラム内にはインクリメント以外出てきていません。
なぜ、こんなにadd命令が多いのでしょう?(512なんて知りません。)

君が足し算を書いていないのに、って思い上がるな(笑)。islower()を君が書いたわけではあるまい。でも、でも調べる手がかりはあるでしょ。512の根拠は簡単にわかったぞ。

movq    (%rax), %rax
括弧内のレジスタにアドレスが入っていたら、()はC言語で言う所の間接演算子(*)と同じ効果?

言うまでもないほど当たり前の事を言うが、レジスタにも、メモリにも、常に何か値が入っている。値が入っていない事なんて、ない。
「レジスタにアドレスが入っていたら」ではなく、「レジスタ%raxの値を、メモリアドレスとして、そのメモリの値を%raxに読み込む」、それだけ。rax = *rax; みたいな事です。

同じレジスタのANDを取ってどうするんでしょうか??

testl命令だけを見たら分からないかもしれないが、

   andl    $512, %eax
   testl    %eax, %eax
   je    .L3

je命令は条件分岐命令です。どんな条件で分岐するか、調べよ。testl命令の意味も、そこにある。このプロセッサのアセンブリ言語で、この3命令は決まり文句の一つと言っていい。

私の本のなかでは、islower()の呼び出しは以下のようになっています

その本は、ほぼ関数呼出でislower()を実現してるようです。それに対して今見てるコードは、islower()をインライン展開で実現してるようです。コンパイラが、どんなコードを生成するかは、コンパイラによっても、コンパイル条件(最適化オプション等々)によっても、違いが生じます。当たり前。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/11 09:57

    あ、すいません。アセンブルの方は修正しますね。

    キャンセル

  • 2017/07/11 10:16

    http://kira000.hatenadiary.jp/entry/2014/08/26/052447

    TEST TEST EAX,EAX if(EAX==0) ZF = 1 EAXの値を0と比較してフラグに反映
    else ZF = 0 EAXが0と等しければZF=1,EAXが0でなければZF=0
    JE(JZ) JE 041001000 if(ZF == 1) ZFが1なら041001000にジャンプ
    GOTO 041001000

    512??
    意味が分からないです・・・・

    「この3命令は決まり文句の一つと言っていい。」
    そうなんですか!

    キャンセル

  • 2017/07/11 10:44 編集

    「rax = *rax; みたいな事です。 」
    待ってください。

    islower()の戻り値は0か0以外です。
    raxは関数の戻り値を入れるのに使用されるはずです。
    なぜ「%raxの中にアドレスが入っている」・・・という事になるのでしょうか?
    この関数の場合、戻り値はポインタではなく、値ですよね・・・・

    キャンセル

  • 2017/07/11 10:58

    __ctype_b_loc@PLT
    に入る直前は、rax = 0x79(121)
    その直後は、rax = 0x7ffff7fce6b0

    movq (%rax), %rax
    で、rax = 0x7ffff7b866c0に変化しています。

    movslq %edx, %rdx
    rdx = 0x79(121)

    movzwl (%rax), %eax
    rdx = 0xf2(242), rax = 0xc608(50696)

    andl $512, %eax
    rax = 0x200(512)

    となっていました。

    キャンセル

  • 2017/07/11 11:15 編集

    2つ上
    >>islower()の戻り値は0か0以外です。
    なんでislower()の話をしているのだろうか?

    __ctype_b_locは、
    const unsigned short * * __ctype_b_loc (void);
    と定義されている。

    short**だから、(rax)にrdx*2を足した上で、(rax)してる。

    キャンセル

  • 2017/07/11 11:24

    横から失礼します。

    andl $512, %eax
    testl %eax, %eax

    は小文字のビットをテストしているのでしょう。 ctype.h の中で小文字を 0x200 で定義してるんじゃないでしょうか?
    (大文字なのかも知れない・・・)
    andlでゼロフラグが立てば次の test 命令はいらないと思いますが、and では立たないんだっけ?

    キャンセル

  • 2017/07/11 11:32

    今調べてみました。
    ubuntu 16.04 の /usr/include/ctype.h では enum として
    _ISlower = _ISbit (1), /* lowercase. */
    _IScntrl = _ISbit (9), /* Control character. */
    ですね。 なんか、的外れなことを言ってるよう泣きが・・・・

    キャンセル

  • 2017/07/11 11:56

    返り値がポインタのポインタになっているということですか?
    ?そうなの?

    キャンセル

  • 2017/07/11 11:57 編集

    short**だから、(rax)にrdx*2を足した上で、(rax)してる。

    なんでポインタのポインタなら、(rax)にrdx*2をする必要があるんでしょう?
    全く分からない・・・・

    https://github.com/evanphx/ulysses-libc/blob/master/src/ctype/__ctype_b_loc.c

    キャンセル

  • 2017/07/11 12:01 編集

    shortは2バイト。たぶん。sizeofで調べて下さい。

    キャンセル

  • 2017/07/11 12:08

    short = 2B
    ・・・・

    2 ^ 16 = 65536 ・・・全く関係ないですね。

    movl -12(%rbp), %edx
    movslq %edx, %rdx
    addq %rdx, %rdx
    addq %rdx, %rax

    rdx には、Cの値が入ります(アドレスですよね)
    C = C+C;
    rax = rax + C;

    int 型からshortへのキャスト・・・・おお?
    いや、違うかな・・・・・

    キャンセル

  • 2017/07/11 12:17 編集

    (deleted)

    キャンセル

  • 2017/07/11 12:31



    __ctype_b_loc = islower()と同義なのかと勘違いしていました。

    call __ctype_b_loc@PLT
    movq (%rax), %rax
    movl -12(%rbp), %edx
    movslq %edx, %rdx
    addq %rdx, %rdx
    addq %rdx, %rax
    movzwl (%rax), %eax
    movzwl %ax, %eax
    andl $512, %eax
    testl %eax, %eax

    どこまでかは正確には分からないのですが、このあたりまでのコードで、islower()を実現しているということですか!

    「それに対して今見てるコードは、islower()をインライン展開で実現してるようです。」
    やっとこれの言っていることの意味がわかりました。

    キャンセル

  • 2017/07/11 12:41

    インライン展開ってことはマクロの可能性もありますが・・・

    https://github.com/evanphx/ulysses-libc/blob/master/src/ctype/__ctype_b_loc.c
    ここに載っているテーブルの意味が分かりませんね。

    キャンセル

  • 2017/07/11 12:49 編集

    各文字のフラグ。フラグというのはislower、isupper、isdigitなどのフラグ。ctype.hを見れば分かります。(なんで直値で書かれているのかは分かりませんが)
    nob.さんが書いていたのはこれのことで、512 = 0x200 = islowerのフラグではないか?という推測でした。

    p.s. 勘違いしてなさそうだったので削除していたコメントは復活させました。

    キャンセル

  • 2017/07/11 12:50 編集

    #define __isctype(c, type) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )type)

    #define islower(c) __isctype((c), _ISlower)
    となっていました。

    以下はnobさんと同じですね。
    _ISlower = _ISbit (1), /* lowercase. */

    #defien _ISbit(bit) ((bit) < 8 ? ((1<<(bit)) << 8) : ((1 << (bit)) >> 8))
    になってますね。

    キャンセル

  • 2017/07/11 12:56

    _ISbit (1) = 0x200 でbingo。

    キャンセル

  • 2017/07/11 12:58

    おおお!
    すごい!
    やっと見つかった感じですかね!

    キャンセル

  • 2017/07/11 13:02 編集

    _ISlower = 0x200なので、
    #define islower(c) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )_ISlower)

    これをインライン展開(?)したら、質問中のアセンブリプログラムが出現するわけですね!

    関数で実装されているものだと勘違いしていました。
    マクロで実装されているから、自分の書いたものとは関係のないものが記述されていたわけですね!

    キャンセル

  • 2017/07/11 13:06

    分からないことを放置して先に進むからこうなる。時間の無駄。

    キャンセル

  • 2017/07/11 13:59

    nob. さん
    > andlでゼロフラグが立てば次の test 命令はいらないと思いますが、and では立たないんだっけ?

    はい。その通りです。なので、and, or 等のビット論理演算命令の直後に test 命令でフラグを変化させ、判定する。これがこの石の定石。

    キャンセル

  • 2017/07/11 14:05

    and 命令だけでは判定ができないので、test 命令でフラグを変化させ、判定する。
    ほおぉ・・・左様ですか。

    キャンセル

  • 2017/07/11 14:14

    >>rubato6809さん
    え!andはZF変化しますよね?

    キャンセル

  • 2017/07/11 14:20

    ん?
    最初の質問のアセンブリコード
    testl %eax, %eax
    これをコメントアウトしてみました。

    正常に動作しますよ!

    キャンセル

  • 2017/07/11 14:21 編集

    例の謎の、movl 0x0, %eax と同じような不要なコードという事になりますが・・・

    キャンセル

  • 2017/07/11 14:30

    andl $512, %eax

    testl %eax, %eax

    論理積を取るものがお互い異なるので、仮にandlでフラグが変化しても、testl命令の際の論理積で、フラグが同じ値に変化するとは限らないような気がするんですが・・・・

    andl命令でフラグを変化できないための補うtestl命令なら、testl $512, %eaxとしなくてはいけないのではないでしょうか?

    キャンセル

  • 2017/07/11 14:43 編集

    > え!andはZF変化しますよね?

    え?そうでしたっけ?この辺りが68Kなんかと違ったと記憶してましたが???
    だとしたら、gccのコード生成、ダサすぎじゃあ。。。

    キャンセル

  • 2017/07/11 14:44

    68kと違うのはmovでフラグが変化するかどうか、ってやつじゃないですかねw

    キャンセル

0

間違いを教えながらベストアンサーにしてもらったままでは申し訳ないので、少しサービス(笑)。

call *(%rax) 
>>%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。
違う。
    絶対アドレス(absolute)の場合は * を付ける。
    相対アドレス(PC relative)の場合は付けない。

違うんですか・・・・同じことだと思ったのですが・・・・

命令が同じでも、オペランドの形式が異なると操作対象が異なる、即ち機械語の動作が異なる。いわゆるアドレッシングモードの件。
上のやり取りを見て、call命令のアドレッシングモードがややこしく感じたので、思いつく限りの呼出方を並べて、as はどう扱うのか試してみました。
subr: は、呼ばれると %rax を +1 して返す。これを、aFunc: は何度も呼び出す(acode.s)。

        .section .rodata
xx:     .quad   subr
        .text
subr:   inc     %rax           # ++rax
        ret
        .global aFunc
aFunc:
        mov     $0, %rax

        call    subr           # 最も普通
        call    (subr)         # 上と同じコード

        call    *(xx)          # xx経由
        call    *xx            # xx経由

        mov     $subr, %rdx    # 絶対アドレスをロード
        call    *%rdx          # 
        call    %rdx           # Warning
        lea     subr(%rip), %rdx # 実効アドレスをロード, PIE
        call    *%rdx          # 
        call    %rdx           # Warning

        lea     xx(%rip), %rdx # アドレスが置かれたメモリのアドレスをロード
        call    *(%rdx)        # xx経由
        call    (%rdx)         # Warning
        ret


呼出側(ccode.c)。

#include <stdio.h>
int aFunc(void);
int main(void)
{
    printf("subr() has been called %d times.\n", aFunc());
    return 0;
}


コンパイルと動作確認はシンプルに。

$ cc ccode.c acode.s 
acode.s: Assembler messages:
acode.s:18: Warning: indirect call without `*'
acode.s:22: Warning: indirect call without `*'
acode.s:26: Warning: indirect call without `*'
$ ./a.out
subr() has been called 10 times.


アセンブラが警告warningを出す命令は、直前の命令と同じ機械語が生成されることが確認できるはず。「お前、手を抜いて'*'を省いたな。今回は'*'を補ってアセンブルしてやるから、次はちゃんと書けよ(笑)」。ちなみに、手元のasはバージョン2.26.1。

さて、callに限らず、分岐命令とは、CPU内部で命令ポインタ%ripの値を変更する命令です。
何の値が%ripに代入されるかという違いがcall命令のアドレッシングモードの違いです。試した命令は次の4種類に整理できそうです。

1.「call ラベル」「call (ラベル)」
例:"call subr", "call (subr)"
前者は最も一般的な形式。機械語に含まれる(機械語にエンコードされる、とも言う)のはラベルまでの距離。いわゆるPC相対分岐です。
%rip = %rip + ラベルまでの距離

2.「call *ラベル」「call *(ラベル)」
例:"call *xx", "call *(xx)"
%rip = ???

3.「call *%レジスタ」「call %レジスタ」
例:"call *%rdx", "call %rdx"
%rip = ???

4.「call *(%レジスタ)」「call (%レジスタ)」
例:"call *(%rdx)", "call (%rdx)"
%rip = ???

%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね

というような、字面・上辺だけで早合点しようとするのではなく、(少なくとも一度は)具体的に・深く・何か工夫して・予想を立てられるなら、それに基づいて・自分の手を動かして・確かめて欲しいものです。ということで、こんな確かめ方もあるよという紹介をしたので、2.〜4.は???の部分をstrike君への穴埋め問題とします笑。技術的に通じる日本語で回答するように。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/12 15:31

    あ、ありがとうございます。
    ちょうどアスタリスクが理解不足だったので!

    キャンセル

  • 2017/07/12 17:58

    「*」はjmp命令やcall命令以外にも使用可能ですか?(jmpとcallしか見たことがないです。)

    キャンセル

  • 2017/07/12 22:45

    さあね。
    どの命令で使えると嬉しいですか?その命令で試してみるといいよ。
    アセンブラがエラーにしなきゃ、使えるってこと。

    キャンセル

  • 2017/07/12 22:52

    あ、確かに

    キャンセル

  • 2017/07/13 16:05 編集

    mov $subr, %rdx # 絶対アドレスをロード
    call *%rdx

    これだけできなんですが、アセンブルエラーです。
    $は即値のsyntaxですよね。
    ラベルに付けられるんですか?

    キャンセル

  • 2017/07/13 16:18

    call *(xx) # xx経由
    call *xx # xx経由

    こちらもエラーですね。
    これができるなら、call *subr もできるはずです。

    アスタリスクは、絶対アドレスが入っているレジスタに対する構文ではないでしょうか?

    キャンセル

  • 2017/07/13 16:29

    レジスタに相対アドレスを書く・・・・なんて出来ません。
    なので、レジスタに関数へのポインタを入れれば、その時点で絶対アドレスとして扱われるはずです。

    「%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。」
    要は同じことですよね。
    レジスタに入る関数のポインタは必ず絶対アドレスになるので・・・・
    例外があれば教えてください。

    キャンセル

  • 2017/07/13 16:45 編集

    call subr # 最も普通
    call (subr)

    これが出来ることの意味は、括弧もラベルに対しても構文ではなく、レジスタに対するものだということが分かります。(ラベルに対しては付けても付けなくもおk!)

    もう1つおかしな部分は、上で書いた事以外に
    call *(xx)
    call *xx

    は、xxはポインタのポインタになっています。
    call xx ならエラーは出ませんが、実行するとsegmentation faultです。

    キャンセル

  • 2017/07/13 23:14

    > mov $subr, %rdx # 絶対アドレスをロード
    > call *%rdx

    どちらの行がアセンブルエラーになるのですか?それとも両方?他にもエラーになる行がありますか?
    要するに、エラー報告として、なってない。どの行がエラーになったのか、不正確・曖昧。念の為、エラーメッセージも見せてもらいたいね。

    > これだけできなんですが、アセンブルエラーです(←通じない日本語w)

    私は、私の手元で、エラーにならず動作するコードを紹介しました。
    アセンブルエラーになるなら、asのバージョンが違うのかもね。君はasのバージョンを確かめましたか?

    > アスタリスクは、絶対アドレスが入っているレジスタに対する構文ではないでしょうか?

    君の「絶対アドレスが入っているレジスタに対する構文」という言い方が、私には逆立ちして聞こえます。機械語の動作やアセンブリ言語の表記は、(「このレジスタには絶対アドレスが入っているぞ!・入ってるはずだ!」「こっちのレジスタに入っている値はアドレスではない」といった)君の主観(或いは評価)で決まるのではないからです。

    私なりに言い換えれば、「この構文でアセンブルされた機械語は、レジスタの値を(絶対)アドレスとして扱う(その結果、〜〜へ飛ぶ)」です。

    > レジスタに相対アドレスを書く・・・・なんて出来ません

    レジスタに、飛び先までの距離(を相対アドレスと呼ぶなら)をロードする事なら、可能ですよ。そうするための、アセンブリコードの書き方はあります。

    > call xx ならエラーは出ませんが、実行するとsegmentation faultです

    それは当然の結果でしょう。ならなかったら奇跡w。
    だけど君は、その理由が理解できていないようだ。違いますか?

    キャンセル

  • 2017/07/14 10:15

    > アスタリスクは、絶対アドレスが入っているレジスタに対する構文

    に似た気持ちを表現するなら
    「レジスタの値は絶対アドレスである、とCPUに解釈させる構文が'*'」ということかな。

    キャンセル

  • 2017/07/14 10:55

    「レジスタの値は絶対アドレスである、とCPUに解釈させる構文が'*'」なら
    call *xx
    なぜラベルに'*'を付けられるんでしょうか?

    call *xxこれができるのに、なぜcall *subrは出来ないんですか?

    アセンブルバージョンとエラーは後で載せます。少々お待ちを!

    キャンセル

  • 2017/07/14 11:01

    call *(xx) # xx経由
    call *xx # xx経由

    mov $subr, %rdx # 絶対アドレスをロード
    call *%rdx #

    これができません。
    残りのは問題ないですね。

    上にも書きましたが、$subr $は即値の構文ではないのですか? なんでラベルに付けられるんでしょう?

    キャンセル

  • 2017/07/14 11:02

    穴埋め問題の回答は、まだですか?
    案外、大事だと私は思っているのでね、よろしく〜w

    キャンセル

  • 2017/07/14 11:08 編集

    例えば、call *xxを追加しただけで・・・・

    /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: 関数 `_start' 内:
    (.text+0x20): `main' に対する定義されていない参照です
    /usr/bin/ld: 最終リンクに失敗しました: 無効な操作です
    collect2: error: ld returned 1 exit status

    となります。
    gasのエラーというより、リンカのエラーですね。
    アドレス解決ができていなんですかね・・・・(わからない)

    私も初心者なので、分かりませんが、とりあえずエラーの出ていない穴埋め問題にチャレンジしますわ。

    エラーが出ている文の文法がちょっと理解できないです。

    キャンセル

  • 2017/07/14 11:16

    どう回答すれば良いのか分からないんですが・・・

    3. %rip = %rdx
    4. %rip = %rdxのアドレスが示してるアドレス(ポインタのポインタ)

    という感じでしょうか?

    キャンセル

  • 2017/07/14 11:37

    gcc (Debian 6.3.0-18) 6.3.0 20170516
    かなり新しいですね。rolloing editionなので

    キャンセル

  • 2017/07/14 11:40 編集

    > 例えば、call *xxを追加しただけで・・・・
    > /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: 関数 `_start' 内:
    > (.text+0x20): `main' に対する定義されていない参照です

    ???
    2つのソースファイル(ccode.c と acode.s)は私と同じにしたか?どのようにコンパイルしたか?私が示したやり方と同じか?どこに、どう「”call *xx”を追加」したか?

    アセンブラのバージョンは
    $ as -v
    とすれば表示される(標準入力待ちになるので、CTRL-Dを打たないと終わらない)。

    キャンセル

  • 2017/07/14 11:42

    コンパイルのやり方は、rubato6809さんと同じですよ。

    最初にエラーが出てきたので、他のやり方でも試してみましたが・・・

    キャンセル

  • 2017/07/14 11:45

    gasは2.28です。

    キャンセル

  • 2017/07/14 11:46

    gcc (Debian 6.3.0-18) 6.3.0 20170516
    は、私のgcc version 5.4.0 20160609 より新しいので、私のasより古いはずはなかろう。そうすると、エラーの原因は、私と同じやり方をしていないから、即ち、早とちりして、自分勝手なやり方で試したから、という想像が成り立つ。

    キャンセル

  • 2017/07/14 11:47

    いえ!、同じようにやりました。

    キャンセル

  • 2017/07/14 11:49 編集

    コンパイルも同じです。
    今再度やり直しました。

    それ以前に、文法的も少々納得がいかな部分があるんですが・・・

    キャンセル

  • 2017/07/14 11:51

    同じファイルで、同じやり方だ、というなら、
    $ as acode.s
    としてみなさい。私だと、次の4行が表示され、a.out ファイルが作られ、正常終了する。
    acode.s: Assembler messages:
    acode.s:18: Warning: indirect call without `*'
    acode.s:22: Warning: indirect call without `*'
    acode.s:26: Warning: indirect call without `*'

    キャンセル

  • 2017/07/14 11:54

    as -a acode.s
    とすれば、アセンブルリストを表示する。

    キャンセル

  • 2017/07/14 11:54

    それもやりました。
    同じくエラーはないですね。

    キャンセル

  • 2017/07/14 11:57

    ダメですね。gasの方は出来ても、リンカのアドレス解決ができていないようです。

    私の回答の答え合わせを・・・お願いします!

    キャンセル

  • 2017/07/14 11:59

    Warning は出ますか?

    アセンブルエラーにならないなら、アセンブリ言語上の文法エラーは無い、という事だ。すると、リンク上のエラーだ。
    君のソースコードをみせなさい。どこか何か、書き間違いをしているに違いない。

    キャンセル

  • 2017/07/14 12:03 編集

    何度もエラーが出てきて出来なかったので、rubato6809さんのをコピー&ペーストしました。
    全く同じですよ。

    > 最終リンカに失敗しました:出力に対するセクションがありません
    とのことです。

    私の回答の答え合わせを!

    キャンセル

  • 2017/07/14 12:06

    > rubato6809さんのをコピー&ペーストしました。全く同じ

    ではシステムの環境を、どちらかに一致させてみないと再現できないかもね。私はそこまで付き合うつもりは無いので。

    キャンセル

  • 2017/07/14 12:10

    あら・・・・
    別のLinux mintを使ってやってみました。
    できました!!

    それで・・・私の回答の答え合わせをお願いします。

    キャンセル

  • 2017/07/14 12:12

    こちらのlinuxはgccのバージョンが古いですね。
    古い方だとできるのかな?

    キャンセル

  • 2017/07/14 14:04

    これについては再度質問します。

    キャンセル

-2

コメントが長くなってしまったので、こちらに書きますね。

#define islower(c) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )_ISlower)

andl $512, %eax
rax = 0x200(512)
の後・・・

testl    %eax, %eax
これがまだ謎ですね・・・・同じものをAND取ってどうするのか分からないですね・・・・

C = C+C;
rax = rax + C;
あとこれの必要性も見えないです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/11 13:44

    最適化かけても消えないですか?

    キャンセル

  • 2017/07/11 13:46

    gccでコンパイルの際には、最適化のオプションは入れていません。

    -O0で最適化無効になるはずです。
    最適化オプションなしのデフォルトでは、自動的に最適化されるんでしたっけ?

    キャンセル

  • 2017/07/11 13:48 編集

    最適化したら「testl %eax, %eax」が無くなりませんか?という意味です。

    キャンセル

  • 2017/07/11 13:50

    試しに、gcc -O2 source.c -S でやってみました。

    キャンセル

  • 2017/07/11 13:51

    call __ctype_b_loc@PLT
    28 movq %r13, %rbp
    29 movq %rax, %r12

    このようになりました。

    キャンセル

  • 2017/07/11 13:51

    ちょっと、分かりにくいので、質問の方に追記いたします。

    キャンセル

  • 2017/07/11 13:55

    どうでもいいけど、回答欄に質問を書かないでください。

    キャンセル

  • 2017/07/11 13:55

    あれ?オプションなしでコンパイルすると自動的に最適化されなかったけ?
    ・・・・されないようですね。

    「testl %eax, %eax」は、なくなりますね。
    call __ctype_b_loc@PLTの後はすごく短くなりますね。

    キャンセル

  • 2017/07/11 13:56

    「回答欄に質問を書かないでください。」
    あ、すいません。考察するスペースが欲しくて、つい・・・

    キャンセル

  • 2017/07/11 14:07

    andl $512, %eax
    この行までで、(*__ctype_b_loc())[(int) (c)] を算出し、(unsigned short int )_ISlowerとandを取っているんですね・・・

    __ctype_b_loc()の内部と
    C = C+C;
    rax = rax + C;
    の関係が分からないですね・・・う~~~ん

    キャンセル

  • 2017/07/11 14:21

    unsigned short table[] というテーブルの場合、&table[0] と &table[1] のアドレスの差が2なのは分かりますか?

    キャンセル

  • 2017/07/11 14:23

    static const unsigned short table[]

    はいはい!差分は2ですね!

    キャンセル

  • 2017/07/11 14:24

    だからx2してるんですよ。

    キャンセル

  • 2017/07/11 14:26

    差分が2でx2・・・?

    それがどうして%rdxなんですか?

    キャンセル

  • 2017/07/11 14:33

    そもそも・・・
    static const unsigned short *const ptable = table+128;

    return (void *)&ptable;

    これでは、ptableは常に同じ値になりますよね・・・・
    パラメータによって変動しないので・・・

    うう~~ん。頭が痛い(´Д`)ハァ…

    キャンセル

  • 2017/07/11 14:43 編集

    >>それがどうして%rdxなんですか?
    movl -12(%rbp), %edx
    これ。

    >>これでは、ptableは常に同じ値になりますよね・・・・
    テーブルの先頭アドレスを取得する関数なのだから当たり前。
    フラグを取り出す関数じゃないよ。

    アセンブリ言語にはshort*なんて無い。全てvoid*だと思えばいい。
    void*でshort*のテーブル(配列)にアクセスするなら添字は2倍になる。

    キャンセル

  • 2017/07/11 15:47

    「テーブルの先頭アドレスを取得する関数」
    ほぇ?ptable = table+128; ptableは先頭ではないですよね? ptable = tableなら先頭ですが・・・

    movq (%rax), %rax で rax = table+128(アドレス)

    その後、rax = table+128+%rdx(c)*2
    その後、(%rax)&512

    キャンセル

  • 2017/07/11 15:50

    %rdx ことCは int 型ですが・・・

    キャンセル

  • 2017/07/11 15:54

    rax = table+128+%rdx(c)*2

    これは・・・rax = table + 128 + (121)*2
    ということですよね・・・

    キャンセル

  • 2017/07/11 15:59

    >> ほぇ?ptable = table+128; ptableは先頭ではないですよね?
    だから「テーブル」と書いたのですが。
    考え方の話です。

    キャンセル

  • 2017/07/11 15:59

    table+128は 大量の0を無視して一番最初の X(0x200)を指します。
    そこから、(121)*2の要素って・・・最後の方の0・・・?

    キャンセル

  • 2017/07/11 16:03 編集

    >>rax = table + 128 + (121)*2 ということですよね・・・
    違います。Cとアセンブリが混ざってます。

    >>(121)*2の要素って・・・最後の方の0・・・?
    これも同様。

    キャンセル

  • 2017/07/11 16:04

    あら?違いますか

    rax = table+128+%rdx(c)*2
    こちらは合っていますか?

    キャンセル

  • 2017/07/11 16:04

    ちゃんと消化しなさい。

    キャンセル

  • 2017/07/11 16:13 編集

    うん?
    rax = table + 128で、rax = 0x7ffff7b866c0

    rax = table + 128 + (121)*2 これで、0x7ffff7b867b2  ・・・・ありゃ?

    どうなってるんだろ・・・

    差は0x2fになってますね。242ですよ。

    キャンセル

  • 2017/07/11 16:17

    short = 2Bより
    table + 128 + 121の配列の位置ということですね!!

    キャンセル

  • 2017/07/11 16:19

    Cの値が121というのは、おかしいですよね?
    c = *p
    Cは一時的にポインタを入れる変数ですが・・・

    キャンセル

  • 2017/07/11 16:30

    Cって大文字で書いているのは何か意味があるのでしょうか?

    char *p; int c; c = *p; でcにポインタが入っていると思っているのならC言語の勉強をやり直して下さい。

    キャンセル

  • 2017/07/11 16:32

    あ、ごめんなさい。
    cはポインタではありませんでしたね。
    すいません。

    大文字は・・・・関係ないです。
    すいません。

    キャンセル

  • 2017/07/11 16:34

    man ascii で y = 121になってますね。
    ああああ~~やっと解決したぁぁ。

    いやぁ
    残りの強敵はこいつですかね。
    testl %eax, %eax

    キャンセル

  • 2017/07/11 16:43

    call *(%rax)

    このアスタリスクについてもまだ未解決ですね。

    キャンセル

  • 2017/07/11 17:14

    >>testl %eax, %eax
    ただの想像ですが、andl $512, %eax までがislower()のコード(インライン展開?)で、
    testl %eax, %eax からが、呼び出し元のislower()の戻り値をチェックするコード。
    この2つを単純にくっつけているために、接合部分に冗長なコードが残ってしまったような気がします。

    >>call *(%rax)
    まずドキュメントを調べて下さい。何度同じことを‥。

    AT&T absolute (as opposed to PC relative) jump/call operands are prefixed by `*'; they are undelimited in Intel syntax.

    キャンセル

  • 2017/07/11 17:27

    「この2つを単純にくっつけているために、接合部分に冗長なコードが残ってしまったような気がします。」
    あ~
    なるほど!

    キャンセル

  • 2017/07/11 17:30 編集

    This means it will jump to the address contained in the register.

    call *(%rax)

    %rax内がアドレスだった場合の関数の呼び出し方法という事ですかね。
    関数のポインタのようなものですね。
    call %raxではダメという事ですね。

    キャンセル

  • 2017/07/11 17:32

    フラグをセットするためのtest命令なら、
    testl $512, %eax
    でなくてはならない気がするんですが・・・・

    キャンセル

  • 2017/07/11 17:44 編集

    どこをどう読んだのか?
    * の意味は "absolute (as opposed to PC relative)" です。

    >>フラグをセットするためのtest命令なら、
    andl $512, %eax を実行後の eax の値は 0 か 512。
    testl %eax, %eax は eax が 0 かどうかチェックしている。
    eax == 0 なら ZF=1
    eax != 0 なら ZF=0

    以上。

    キャンセル

  • 2017/07/11 17:48 編集

    なんで、ANDをとったら、0かどうかわかるんだろ・・・

    https://stackoverflow.com/questions/19088064/what-is-the-meaning-of-putting-a-star-before-a-register
    「* の意味は "absolute (as opposed to PC relative)" です。」

    えー。絶対参照・・?
    関数のアドレスが入っていれば、*をつけるってことですね。

    キャンセル

  • 2017/07/11 17:52

    andl $512, %eax を実行後の eax の値は 0 か 512。

    ビット列でANDを取ったら、0か512?
    2通りしかないってことですよね?
    ん?なんで?

    キャンセル

  • 2017/07/11 18:08

    また脊髄反射。
    何も考えずに質問して、回答が来たら納得はするけど何一つ身に付いていない。
    分かった気になっているだけ。

    キャンセル

  • 2017/07/11 18:11 編集

    え、ちょっと待ってください。
    andl $512, %eaxで、%eaxの中に、0以外の値が入ってたら、普通に0か512以外にも数字が出てきますが・・・

    あ、すいません。
    512 = 10000・・・ 勘違いしていました。
    0か512以外は出てこないですね。

    キャンセル

  • 2017/07/11 18:17 編集

    call *(%rax)
    %raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。

    http://d.hatena.ne.jp/pakepion/20081021/1224592877

    ふぅ、解決いたしましたわ。
    fuzzballさんに評価を入れられないので、rubato6809さんをBestAnswerにいたしますわ。

    キャンセル

  • 2017/07/11 18:21 編集

    >>%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。
    違う。
    絶対アドレス(absolute)の場合は * を付ける。相対アドレス(PC relative)の場合は付けない。

    スルー耐性の高さだけは褒めてあげるよw

    キャンセル

  • 2017/07/11 18:23

    む!

    違うんですか・・・・同じことだと思ったのですが・・・・

    キャンセル

同じタグがついた質問を見る

  • C

    4528questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • アセンブリ言語

    116questions

    アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。