Как же получить сырой бинарник с языка C++ из под Windows

Тема в разделе "WASM.BEGINNERS", создана пользователем s3dworld, 18 янв 2011.

  1. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Всем доброго вечера!

    Вчера весь день и весь вечер бился над решением данного вопроса, но так ничего путного и не нашёл. Собственно я успел опробовать только два средства: Visual C++ (ml и link) и MinGW (g++ и ld). И хочу показать что у меня получилось.

    Сейчас речь пойдёт о Visual C++ (ml и link). Создал файл main.cpp со следующим кодом:

    Код (Text):
    1. bool main(int* _value)
    2. {
    3.     if(!_value) return false;
    4.    
    5.     *_value=5;
    6.    
    7.     return true;
    8. }
    Обрабатываю:

    Код (Text):
    1. SET INCLUDE=C:\Program Files\Microsoft Visual Studio 10.0\VC\include\
    2. SET LIB=C:\Program Files\Microsoft Visual Studio 10.0\VC\lib\
    3. cl main.cpp /c /nologo /GS- /GR- /TP /Gm /Zi
    4. link main.obj /ENTRY:main /RELEASE /OUT:"main.bin" /SUBSYSTEM:NATIVE /NODEFAULTLIB /MACHINE:X86 /BASE:0x0 /MERGE:.text=.data /MERGE:.rdata=.data /IGNORE:4254
    5. objcopy main.bin -I pe-i386 -O binary
    6. del main.obj
    7. del vc100.idb
    8. del vc100.pdb
    9. pause
    Получил файл main.bin, который занимает 26 байт. Вот его hex-содержимое:

    Код (Text):
    1. 00000000: 55 8B EC 83 7D 08 00 75 04 32 C0 EB 0B 8B 45 08 C7 00 05 00 │ UЛьГ} u2└ы ЛE╟ 
    2. 00000014: 00 00 B0 01 5D C3                                           │   ░]├
    А вот дизассемблированный код:

    Код (Text):
    1. 00000000: 55                      push        ebp
    2. 00000001: 8BEC                    mov         ebp,esp
    3. 00000003: 837D0800                cmp         dw [ebp+008h],000h
    4. 00000007: 7504                    j) jne      00000000Dh
    5. 00000009: 32C0                    xor         al,al
    6. 0000000B: EB0B                    j) jmp      000000018h
    7. 0000000D: 8B4508                  mov         eax,[ebp+008h]
    8. 00000010: C70005000000            mov         dw [eax],000000005h
    9. 00000016: B001                    mov         al,001h
    10. 00000018: 5D                      pop         ebp
    11. 00000019: C3                      ret
    Собственно по генерированному коду (именно лишь по этому примеру) никаких вопросов нет. Вполне можно было бы использовать данный компилятор для разработки операционной системы. Но только меня мучает вопрос, касаемо смещения. Смещение при компоновке задаётся с помощью параметра (ключа) /BASE. Но ведь Visual C++ (ml и link) не умеет компилировать сырой бинарник, поэтому он смещение сделает не то, которое мы хотим получить. Например, если я укажу ему /BASE:0x00008000, наверняка же в действительности смещение получится (после обработки objcopy) другим (например прибавится 1024 байта или ещё что-то). С одной стороны можно рассчитать нужное смещение и указать его (хотя этот вариант мне не нравится). А с другой стороны, если нужно писать программы, которые будут работать по адресу 0x00000000, то смещение такое мы не добъёмся (так как PE-заголовок и прочее).

    Теперь перейду к MinGW (g++ и ld). Создаю файл main.cpp со следующим кодом:

    Код (Text):
    1. extern "C" bool start(int* _value);
    2.  
    3. bool start(int* _value)
    4. {
    5.     if(!_value) return false;
    6.    
    7.     *_value=5;
    8.    
    9.     return true;
    10. }
    Обрабатываю:

    Код (Text):
    1. g++ -ffreestanding -c -nodefaultlibs -nostdlib -fno-exceptions -o main.o main.cpp
    2. ld -Ttext 0x00000000 --entry _start --file-alignment 1 --section-alignment 1 -o data.bin main.o
    3. objcopy.exe data.bin -O binary
    4. pause
    Смотрим дамп объектного файла main.o:

    Код (Text):
    1. main.o:     file format pe-i386
    2.  
    3.  
    4. Disassembly of section .text:
    5.  
    6. 00000000 <_start>:
    7.    0:   55                      push   %ebp
    8.    1:   89 e5                   mov    %esp,%ebp
    9.    3:   83 7d 08 00             cmpl   $0x0,0x8(%ebp)
    10.    7:   75 04                   jne    d <_start+0xd>
    11.    9:   b0 00                   mov    $0x0,%al
    12.    b:   eb 0b                   jmp    18 <_start+0x18>
    13.    d:   8b 45 08                mov    0x8(%ebp),%eax
    14.   10:   c7 00 05 00 00 00       movl   $0x5,(%eax)
    15.   16:   b0 01                   mov    $0x1,%al
    16.   18:   c9                      leave
    17.   19:   c3                      ret
    18.   1a:   90                      nop
    19.   1b:   90                      nop
    В общем то всё практически нормально, только вот зачем то он два nop вставил. Мы получили файл data.bin, который занимает 64 байта (в два с лишним раза больше чем от link). Вот его hex-представление:

    Код (Text):
    1. 00000000: 55 89 E5 83 7D 08 00 75 04 B0 00 EB 0B 8B 45 08 C7 00 05 00 │ U╣е│} u▀ л ╗EЗ 
    2. 00000014: 00 00 B0 01 C9 C3 90 90 FF FF FF FF 00 00 00 00 FF FF FF FF │   ▀ЙГ└└яяяя    яяяя
    3. 00000028: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │
    4. 0000003C: 00 00 00 00                                                 │
    А вот дизассемблированный код:

    Код (Text):
    1. 00000000: 55                      push        ebp
    2. 00000001: 89E5                    mov         ebp,esp
    3. 00000003: 837D0800                cmp         dw [ebp+008h],000h
    4. 00000007: 7504                    j) jne      00000000Dh
    5. 00000009: B000                    mov         al,000h
    6. 0000000B: EB0B                    j) jmp      000000018h
    7. 0000000D: 8B4508                  mov         eax,[ebp+008h]
    8. 00000010: C70005000000            mov         dw [eax],000000005h
    9. 00000016: B001                    mov         al,001h
    10. 00000018: C9                      leaved
    11. 00000019: C3                      ret
    12. 0000001A: 90                      nop
    13. 0000001B: 90                      nop
    14. 0000001C: FF                      db          0FFh
    15. 0000001D: FF                      db          0FFh
    16. 0000001E: FF                      db          0FFh
    17. 0000001F: FF00                    inc         dw [eax]
    18. 00000021: 0000                    add         [eax],al
    19. 00000023: 00FF                    add         bh,bh
    20. 00000025: FF                      db          0FFh
    21. 00000026: FF                      db          0FFh
    22. 00000027: FF00                    inc         dw [eax]
    23. 00000029: 0000                    add         [eax],al
    24. 0000002B: 0000                    add         [eax],al
    25. 0000002D: 0000                    add         [eax],al
    26. 0000002F: 0000                    add         [eax],al
    27. 00000031: 0000                    add         [eax],al
    28. 00000033: 0000                    add         [eax],al
    29. 00000035: 0000                    add         [eax],al
    30. 00000037: 0000                    add         [eax],al
    31. 00000039: 0000                    add         [eax],al
    32. 0000003B: 0000                    add         [eax],al
    33. 0000003D: 0000                    add         [eax],al
    34. 0000003F: 00                      db          000h
    Получается что код разный. Но не это важно. Важно то, что файл больно большой, что там мусор. Если кому-то есть что добавить по данному вопросу, пожалуйста, говорите.

    Я же хочу из под Windows создавать сырые бинарники из языка C++, для которых я смогу устанавливать любое смещение, где не будет мусора. Кто что посоветует?
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    во-первых, то, чот ты называешь "смещением", на самом деле база.
    во-вторых, зачем тебе "сырые" бинарники из С++?
    компилируй в PE или ELF, а на асме сделай небольшой лоадер.
     
  3. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Great
    Затем, чтобы только лишь на C++ делать. Ну а если всё таки по существу моей проблемы, есть что-то?
     
  4. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    На GCC + Binutils, подозреваю, это сделать можно. Во всяком случае, я для АРМа получал бинарник. Правда, писал на смеси ассемблера и Ады (Си/Си++ ненавижу и использую только под страхом смертной казни), но суть проблемы не меняется. Для этого пришлось компоновщику писать умный скрипт, чтобы он правильно настроил секции на нужные мне адреса и разместил их в нужном порядке (и только те, что нужны), ну а затем уже полученный эльф превратить в бин.
     
  5. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    SII
    То есть простыми путями никак?
     
  6. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    Я таких способов не знаю. И вообще, что значит: простыми путями? Если у кого-то мозгов меньше, чем у блондинки, то ему и неча заниматься программированием вообще, не говоря уж о системном, ну а если мозги есть, то в чём проблема с освоением "непростых" путей? С моей точки зрения, эта задача элементарна; во всяком случае, я её решил часа за три, и это с учётом того, что ранее никогда не использовал GCC и никогда не писал под АРМ. В общем, документацию читать надо, а не по дюжине форумов флудить в надежде, что кто-нибудь решит все задачи и принесёт решение на блюдечке с голубой каёмочкой.
     
  7. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    SII
    Спасибо!
     
  8. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    mycode.ld:
    Код (Text):
    1. ENTRY(_start);
    2.  
    3. OUTPUT_FORMAT(binary);
    4.  
    5. SECTIONS
    6. {
    7.     . = 0x7C00;
    8.  
    9.     .text : AT(0x7C00)
    10.     {
    11.         *(.text);    
    12.     }
    13.  
    14.     .data :
    15.     {
    16.         *(.data);
    17.     }
    18.    
    19.     /DISCARD/ :
    20.     {
    21.         *(.drectve);
    22.         *(/4);
    23.         *(/18);
    24.         *(/30);
    25.         *(/42);
    26.         *(/55);
    27.         *(/66);
    28.         *(/82);
    29.         *(/98);
    30.         *(/113);
    31.     }
    32. }
    Makefile:
    Код (Text):
    1. CC = gcc
    2. LD = i586-elf-ld
    3. CFLAGS = -c -g -Os -march=i686 -ffreestanding -Wall -Werror -Wno-main -fno-builtin -Isrc -Isrc
    4. LDFLAGS = -static -nostdlib --strip-all --nmagic
    5.  
    6. $(LD) $(LDFLAGS) -Tmycode.ld -o myobj.obj
     
  9. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    n0name
    А где Вы такой ld брали? Это под Windows?
     
  10. Voodoo

    Voodoo New Member

    Публикаций:
    0
    Регистрация:
    9 апр 2003
    Сообщения:
    297
    Адрес:
    Новосибирск
    есть еще -fpic у gcc, для генерации базонезависимого кода. правда я не пробовал, как оно работает.
     
  11. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    > А где Вы такой ld брали? Это под Windows?
    перекомпилировал кросс-клмпилер под mingw.
     
  12. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    n0name
    Вы практически вовремя написали.

    Я тут в Интернете нашёл CrossTools Complete. Так вот, пишу так:

    Код (Text):
    1. i586-elf-g++ -ffreestanding -c -nodefaultlibs -nostdlib -fno-exceptions -o main.o main.cpp
    2. i586-elf-ld --oformat binary -Ttext 0x00000000 --entry start -o data.bin main.o
    3. del main.o
    4. pause
    И у меня всё на ура делается. Получается без мусора. Решил скомпилировать с 64-битным кодом:

    Код (Text):
    1. i586-elf-g++ -m64 -ffreestanding -c -nodefaultlibs -nostdlib -fno-exceptions -o main.o main.cpp
    2. i586-elf-ld --oformat binary -Ttext 0x00000000 --entry start -o data.bin main.o
    3. del main.o
    4. pause
    Но в ответ:

    Код (Text):
    1. E:\03>i586-elf-g++ -m64 -ffreestanding -c -nodefaultlibs -nostdlib -fno-exceptio
    2. ns -o main.o main.cpp
    3. main.cpp:1: sorry, unimplemented: 64-bit mode not compiled in
    4.  
    5. E:\03>i586-elf-ld --oformat binary -Ttext 0x00000000 --entry start -o data.bin m
    6. ain.o
    7. i586-elf-ld: main.o: No such file: No such file or directory
    8.  
    9. E:\03>del main.o
    10. Не удается найти E:\03\main.o
    11.  
    12. E:\03>pause
    13. Для продолжения нажмите любую клавишу . . .
    Никто не знает где же сказать полную версию?
     
  13. Voodoo

    Voodoo New Member

    Публикаций:
    0
    Регистрация:
    9 апр 2003
    Сообщения:
    297
    Адрес:
    Новосибирск
    перекомпилируй с поддержкой x64.
     
  14. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Весь интернет облазил не нашёл что мне нужно. Может быть кто-нибудь подкинет ссылочку на x86_64-pc-elf-gcc для Windows x86?
     
  15. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    я же написал - монжо самому перекомпилировать под ту платформу, которая нужна.
     
  16. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923