Помогите разобраться с источником кода

Тема в разделе "WASM.BEGINNERS", создана пользователем kol1978, 16 фев 2025 в 15:06.

  1. kol1978

    kol1978 New Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    29
    из кода на Си
    —------------------nano asm.c
    #include <stdio.h>
    int main() {
    register int *foo asm ("r12") = 77;
    return *foo;
    }
    ------------------------------------получил следующий код:
    ---------------nano asm.s
    main:
    pushq %r12
    xorl %eax, %eax
    movl $77, (%r12)
    popq %r12
    ret
    ------------------------------------(и) objdump -d asm, выдает следующее:
    ~/C$ objdump -d asm
    asm: file format elf64-x86-64
    Disassembly of section .init:
    0000000000401000 <_init>:
    401000: f3 0f 1e fa endbr64
    401004: 48 83 ec 08 sub $0x8,%rsp
    401008: 48 8b 05 e9 2f 00 00 mov 0x2fe9(%rip),%rax # 403ff8 <__gmon_start__@Base>
    40100f: 48 85 c0 test %rax,%rax
    401012: 74 02 je 401016 <_init+0x16>
    401014: ff d0 call *%rax
    401016: 48 83 c4 08 add $0x8,%rsp
    40101a: c3 ret
    Disassembly of section .text:
    0000000000401020 <main>:
    401020: f3 0f 1e fa endbr64
    401024: 41 54 push %r12
    401026: 31 c0 xor %eax,%eax
    401028: 41 c7 04 24 4d 00 00 movl $0x4d,(%r12)
    40102f: 00
    401030: 41 5c pop %r12
    401032: c3 ret
    401033: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
    40103a: 00 00 00
    40103d: 0f 1f 00 nopl (%rax)
    0000000000401040 <_start>:
    401040: f3 0f 1e fa endbr64
    401044: 31 ed xor %ebp,%ebp
    401046: 49 89 d1 mov %rdx,%r9
    401049: 5e pop %rsi
    40104a: 48 89 e2 mov %rsp,%rdx
    40104d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
    401051: 50 push %rax
    401052: 54 push %rsp
    401053: 45 31 c0 xor %r8d,%r8d
    401056: 31 c9 xor %ecx,%ecx
    401058: 48 c7 c7 20 10 40 00 mov $0x401020,%rdi
    40105f: ff 15 8b 2f 00 00 call *0x2f8b(%rip) # 403ff0 <__libc_start_main@GLIBC_2.34>
    401065: f4 hlt
    401066: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
    40106d: 00 00 00
    0000000000401070 <_dl_relocate_static_pie>:
    401070: f3 0f 1e fa endbr64
    401074: c3 ret
    401075: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
    40107c: 00 00 00
    40107f: 90 nop
    0000000000401080 <deregister_tm_clones>:
    401080: b8 28 40 40 00 mov $0x404028,%eax
    401085: 48 3d 28 40 40 00 cmp $0x404028,%rax
    40108b: 74 13 je 4010a0 <deregister_tm_clones+0x20>
    40108d: b8 00 00 00 00 mov $0x0,%eax
    401092: 48 85 c0 test %rax,%rax
    401095: 74 09 je 4010a0 <deregister_tm_clones+0x20>
    401097: bf 28 40 40 00 mov $0x404028,%edi
    40109c: ff e0 jmp *%rax
    40109e: 66 90 xchg %ax,%ax
    4010a0: c3 ret
    4010a1: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
    4010a8: 00 00 00 00
    4010ac: 0f 1f 40 00 nopl 0x0(%rax)
    00000000004010b0 <register_tm_clones>:
    4010b0: be 28 40 40 00 mov $0x404028,%esi
    4010b5: 48 81 ee 28 40 40 00 sub $0x404028,%rsi
    4010bc: 48 89 f0 mov %rsi,%rax
    4010bf: 48 c1 ee 3f shr $0x3f,%rsi
    4010c3: 48 c1 f8 03 sar $0x3,%rax
    4010c7: 48 01 c6 add %rax,%rsi
    4010ca: 48 d1 fe sar %rsi
    4010cd: 74 11 je 4010e0 <register_tm_clones+0x30>
    4010cf: b8 00 00 00 00 mov $0x0,%eax
    4010d4: 48 85 c0 test %rax,%rax
    4010d7: 74 07 je 4010e0 <register_tm_clones+0x30>
    4010d9: bf 28 40 40 00 mov $0x404028,%edi
    4010de: ff e0 jmp *%rax
    4010e0: c3 ret
    4010e1: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
    4010e8: 00 00 00 00
    4010ec: 0f 1f 40 00 nopl 0x0(%rax)
    00000000004010f0 <__do_global_dtors_aux>:
    4010f0: f3 0f 1e fa endbr64
    4010f4: 80 3d 2d 2f 00 00 00 cmpb $0x0,0x2f2d(%rip) # 404028 <__TMC_END__>
    4010fb: 75 13 jne 401110 <__do_global_dtors_aux+0x20>
    4010fd: 55 push %rbp
    4010fe: 48 89 e5 mov %rsp,%rbp
    401101: e8 7a ff ff ff call 401080 <deregister_tm_clones>
    401106: c6 05 1b 2f 00 00 01 movb $0x1,0x2f1b(%rip) # 404028 <__TMC_END__>
    40110d: 5d pop %rbp
    40110e: c3 ret
    40110f: 90 nop
    401110: c3 ret
    401111: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)
    401118: 00 00 00 00
    40111c: 0f 1f 40 00 nopl 0x0(%rax)
    0000000000401120 <frame_dummy>:
    401120: f3 0f 1e fa endbr64
    401124: eb 8a jmp 4010b0 <register_tm_clones>
    Disassembly of section .fini:
    0000000000401128 <_fini>:
    401128: f3 0f 1e fa endbr64
    40112c: 48 83 ec 08 sub $0x8,%rsp
    401130: 48 83 c4 08 add $0x8,%rsp
    401134: c3 ret
    -------------------------------------------------------
    0000000000401020 <main> - это вроде понятно... но откуда появляется код в остальных частях (0000000000401120 <frame_dummy> и тд)??? И! код в <_fini> - реально нужен/для чего этот "плюс минус"? Где об этом можно почитать?
     
  2. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.585
    kol1978, оформите это под тег code, невозможно же читать
    А так, вероятно, это библиотека Си
     
  3. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    142
    Комментариях к исходникам вашего компилятора. Все о чем вы спрашиваете это самодеятельность компилятора и/или требование текущей версии glibc. В остальном код довольно прост. Тут вызывается start, который выполняет main из glibc, чтобы инициализировать библиотеку и после уже glibc возвращает управление программе на точку main.
     
  4. kol1978

    kol1978 New Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    29
    Да - думаю все так... но! 1 - через "комментарии кода компилятора" это циклопическая задача = невозможно для отдельно взятого человека. 2 - забыл упомянуть что это код ELF файла linux...т.е. это тоже накладывает доп инфу/вопросы. 3 - "выполняет main из glibc, чтобы инициализировать библиотеку и после уже glibc " скорее всего то что происходит можно так описать... но для меня это звучит: "кто на ком стоял?"(glibc и есть библиотека)/ не понятно... поэтому решил начать с конца: "код в <_fini> - реально нужен/для чего этот "плюс минус"???? :
    Код (Text):
    1. 0000000000401128 <_fini>:
    2. 401128: f3 0f 1e fa endbr64
    3. 40112c: 48 83 ec 08 sub $0x8,%rsp
    4. 401130: 48 83 c4 08 add $0x8,%rsp
    5. 401134: c3 ret
    endbr64 — часть технологии Intel Control-Flow Enforcement (CET), которая обеспечивает аппаратную защиту от атак, манипулирующих потоком управления, чтобы использовать существующий код в злонамеренных целях. этот код (sub $0x8,%rsp) часть механизма защиты ?
    --- Сообщение объединено, 17 фев 2025 в 06:48 ---
    это тоже хороший вопрос... уже можно идти читать комментарии кода библиотеки :)) шучу....
    Код (C):
    1. int main() {
    2. register int *foo asm ("r12") = 77;
    3. return *foo;
    4. }
    заголовок можно убрать...но ggc14 не будет компилировать, а вот gcc12 например будет:
    Код (ASM):
    1. main:
    2.         pushq   %rbp
    3.         movq    %rsp, %rbp
    4.         pushq   %r12
    5.         movl    $77, %r12d
    6.         movq    %r12, %rax
    7.         movl    (%rax), %eax
    8.         movq    -8(%rbp), %r12
    9.         leave
    10.         ret
    (очевидно что никаких вызовов нет...это про библиотеки) думаю это благодаря не стандартизированному обращению к регистрам ЦП : asm ("r12") и это не суть... код выбирался максимально простой намеренно и плюсом к тому - содержащий "фундаментальный касяк программирования на Си"(register int *foo asm ("r12") = 77; - прямое обращение к регистрам).
    Еще добавлю: по моему endbr64 добавлен для того что бы именно такой код не работал:
    Код (C):
    1. #include <stdio.h>
    2. #pragma code_seg(".shell")
    3. __declspec(allocate(".shell"))
    4. static const unsigned char s_readCs[]
    5. {
    6.     0x66, 0x8C, 0xC8, // mov ax, cs
    7.     0xC3              // ret
    8. };
    9. typedef unsigned short (*ReadCs)();
    10. unsigned short _asm_read_cs()
    11. {
    12.     return ((ReadCs)&s_readCs[0])();
    13. }
    14. int main()
    15. {
    16.     printf("0x%X\n", _asm_read_cs());
    17.     return 0;
    18. }
    очень интересно мнение автора кода :) и как он будет выглядеть на GCC?
     
  5. kol1978

    kol1978 New Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    29
    ggc14 - очепятка...нужно x86-64 gcc 14.2
     
  6. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    505
    Нужно понимать, что C/C++ это не языки в вакууме как ассемблер - у них есть подлежащая инфраструктура которая libc.
    Особенно сложно с этим в C++ где есть new/delete и механизм исключений, но даже в plain C есть проблемки - например операция копирования a = b может привести для сложных типов к call _some_inner_libc_func.
    И первая линия обвязки происходит вокруг функции main - это не настоящая точка входа в исполнимый файл - на самом деле настоящая точка входа находится внутри libc и в ней происходит масса нужных вещей таких как инициализация глобальных переменных, подготовка параметров командной строки так как их ожидает int main(int argc, char **argv) и вопросы инициализации многопоточности и всякое такое. Где то под конец настоящей точки входа находится call main <--- наш main, а после еще всякие деинициализации и завершения занятых у оси ресурсов в обратном порядке.

    Строго говоря в изначальном языке C функция main не просто не особенная, а самая бытовая-типовая вообще ничем совершенно не отличающаяся от прочих пользовательских функций кроме того специфического факта, что где то в недрах libc есть call main - а в соответствии со соглашением о вызовах функций C нет ничего страшного если она будет заявлена без своих правильных параметров и не будет к ним прикасаться - чистит от параметров стек вызывающий код, поэтому int main(), int main(int argc) и void main(int argc, char **argv) спокойно работают разве что в последнем случае еще результат будет случайно-мусорный (а это уже реально неаккуратно в POSIX).

    Не знаю насчёт nano C, но все полновесные компиляторы типа clang/gcc/msvc имеют опции компиляции/линкера типа nostdlib и entrypoint чтобы можно было избавится от всего этого, но ценой того, что собственно функциями libc зачастую станет невозможно пользоваться - многие из них требуют правильной вот этой вот инициализации.
    Если иметь это ввиду, то можно делать экзешники на C размером сотни байт и тому подобные трюки.
     
    kol1978 нравится это.
  7. kol1978

    kol1978 New Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    29
    если "nano C" это из моей писанины то - nanao это текстовый редактор...и у меня привычка писать nano в начале с именем файла так как очень часто делаю "копипасту" этого : nano hello.S , к примеру для создания ф. с кодом на ассемблере... речь о GCC , G++ linux во всех случаях кроме ISPC (указываю всегда). "plain C" - что вы имели в виду? и если знаете (есть) - можно по примеру с точкой входа _start привести пример для входа в libc?
    PS например так :
    gcc -static -no-pie -Os -m64 -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -Wall -S asm.c -o asm.s
    gcc -static -no-pie -Wall asm.s -o asm
    :drinks:
     
  8. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    142
    Вот вторую команду заменяем на ld и читаем к ней параметры
     
  9. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    505
    Си без плюсов, когда не g++, а gcc.

    Ну вот тут есть упраженения на тему: https://www.opennet.ru/base/dev/smallest_code.txt.html но в целом тема довольно глубокая и в двух словах не расскажешь.