Pertanyaan Borland x86 inlined assembler; dapatkan alamat label?


Saya menggunakan Borland Turbo C ++ dengan beberapa kode assembler inline, jadi agaknya Turbo Assembler (TASM) kode assembly gaya. Saya ingin melakukan hal-hal berikut:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

Jadi alamat SomeLabel ditempatkan ke EAX. Ini tidak berfungsi dan kompiler mengeluhkan: Simbol tidak ditentukan 'SomeLabel'.

Di Microsoft Assembler (MASM), simbol dolar ($) berfungsi sebagai penghitung lokasi saat ini, yang akan berguna untuk tujuan saya. Tetapi sekali lagi ini tampaknya tidak bekerja di Borlands Assember (ekspresi kesalahan sintaks).

Pembaruan: Untuk menjadi sedikit lebih spesifik, saya memerlukan compiler untuk menghasilkan alamat yang bergerak ke eax sebagai konstanta selama kompilasi / menghubungkan dan tidak pada waktu berjalan, sehingga akan dikompilasi seperti "mov eax, 0x00401234".

Adakah yang bisa menyarankan cara mendapatkan ini bekerja?

UPDATE: Untuk menanggapi pertanyaan Pax (lihat komentar), Jika alamat dasar diubah pada waktu berjalan oleh loader Windows, gambar DLL / EXE PE akan dipindahkan oleh pemuat Windows dan alamat label akan ditambal pada waktu proses oleh loader untuk menggunakan alamat berbasis ulang sehingga menggunakan nilai waktu kompilasi / tautan untuk alamat label tidak menjadi masalah.

Banyak terima kasih sebelumnya.


8
2017-10-16 15:59


asal


Jawaban:


Terakhir kali saya mencoba membuat beberapa kode assembly yang sesuai dengan Borland, saya menemukan batasan bahwa Anda tidak dapat memberi label forward-reference. Tidak yakin apakah itu yang Anda temui di sini.


4
2017-10-16 23:55



Segala sesuatu yang dapat saya temukan tentang Borland menunjukkan bahwa ini seharusnya berhasil. Pertanyaan serupa di situs lain (sini dan sini) menunjukkan bahwa Borland dapat menangani rujukan ke depan untuk label, tetapi bersikeras pada label berada di luar blok asm. Namun, karena label Anda sudah berada di luar blok asm ...

Saya ingin tahu apakah kompiler Anda akan memungkinkan Anda untuk menggunakan label ini di dalam, misalnya, instruksi jmp. Ketika bermain-main dengan itu (diakui, pada kompiler yang sama sekali berbeda), saya menemukan kecenderungan sial bagi compiler untuk mengeluh tentang jenis operan.

Sintaksnya sangat berbeda, dan ini adalah usaha pertama saya dalam inline asm dalam waktu yang lama, tetapi saya yakin saya sudah cukup memalukan ini untuk bekerja di bawah gcc. Mungkin, meskipun ada perbedaan, ini mungkin berguna bagi Anda:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

Ini menghasilkan:

...
        movl    $.L2, %eax
...
.L2:

Operator && adalah ekstensi non-standar, saya tidak mengharapkannya berfungsi di mana pun selain gcc. Semoga ini bisa membangkitkan beberapa ide baru ... Semoga berhasil!

Sunting: Meskipun terdaftar sebagai Microsoft spesifik, sini adalah contoh lain dari melompat ke label.


4
2018-01-28 12:49



3 saran:

1) letakkan '_' di depan SomeLabel di rakitan sehingga menjadi "mov eax, _SomeLabel ". Biasanya kompilator akan menambahkan satu ketika menerjemahkan C ke dalam perakitan.

Atau

2) letakkan label di bagian perakitan. Ini akan mencegah compiler menambahkan '_'.

Atau

3) komentar majelis, kompilasi, dan lihat file daftar (* .lst) untuk melihat apa nama labelnya.


1
2017-10-16 16:34



Apakah lingkungan Turbo C ++ memiliki cara untuk mengatur opsi untuk TASM (saya tahu bahwa beberapa Borland IDE melakukannya)?

Jika ya, lihat apakah mengubah opsi untuk "Kelulusan maksimum (/ m)" menjadi 2 atau lebih membantu (mungkin default ke 1 pass).

Juga, jika Anda menggunakan nama label panjang yang mungkin menimbulkan masalah - setidaknya satu IDE memiliki set default ke 12. Ubah "Opsi panjang simbol maksimum (/ mv)".

Informasi ini didasarkan pada Borland's RAD Studio IDE:


1
2018-02-03 09:14



Beberapa hal lagi (gambar dalam kegelapan) untuk dicoba:

  • lihat apakah menggunakan instruksi perakitan berikut membantu:

    mov eax, offset SomeLabel
    
  • kebanyakan kompiler dapat menghasilkan daftar perakitan kode yang mereka hasilkan (tidak yakin apakah Turbo C ++ dapat, karena Codegear / Embarcadero memposisikannya sebagai kompiler, bebas-profesional).

    Coba buat daftar dengan kode C yang menggunakan label (sebagai goto target misalnya), dengan beberapa perakitan inline dalam fungsi yang sama - tetapi jangan mencoba untuk mengakses label dari perakitan. Ini sehingga Anda bisa mendapatkan kompilator tanpa kesalahan dan daftar perakitan. Sesuatu seperti:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

    Lihatlah daftar perakitan dan lihat apakah majelis yang dihasilkan menghiasi nama label dengan cara yang mungkin dapat Anda tiru dalam rakitan inline.


1
2018-02-03 19:22



Dari apa yang saya ingat, Anda tidak dapat menggunakan label eksternal (C ++) dalam perakitan inline Anda, meskipun Anda dapat memiliki label bergaya TASM di blok asm yang dapat direferensikan oleh instruksi perakitan itu sendiri. Saya pikir saya akan menggunakan bendera dan pernyataan switch pasca-assembler untuk menangani percabangan. Sebagai contoh:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}

0
2017-10-16 16:37



Saya tidak tahu tentang compiler / assembler Anda secara khusus, tetapi trik yang saya gunakan cukup sedikit adalah memanggil lokasi berikutnya dan kemudian pop stack ke dalam register Anda. Pastikan panggilan yang Anda buat hanya mendorong alamat pengirim.


0
2017-10-16 17:56



Saya pikir masalah yang Anda hadapi adalah bahwa label di dalam __asm blok dan label dalam kode C ++ adalah dua hal yang sangat berbeda. Saya tidak berharap bahwa Anda bisa mereferensikan label C ++ dengan cara itu dari perakitan inline, tapi saya harus mengatakan itu sudah sangat lama sejak saya menggunakan Turbo C ++.

Sudahkah Anda mencoba lea instruksi bukan mov?


0
2018-01-27 09:44



Hanya menebak karena saya belum pernah menggunakan inline assembler dengan kompiler C / ++ ...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

Saya tidak tahu sintaks TASM yang tepat.


0
2018-01-28 10:22