Как метки выполняются в сборке?

Я новичок в ассемблере, поэтому, пожалуйста, будьте со мной полегче, но я запутался в этикетках. Я просто не понимаю, как они работают. Являются ли они функциями, или одна заканчивается и начинается другая? Я имею в виду, что есть 2 ярлыка

Label1: 
    ; random code
Label2:
    ; some more random code

Будет ли выполнение Label1 завершено, или оно затем перейдет к Label2 и выполнит и его? Извините, если это очень простой вопрос, но я просто не понимаю его.


person NewOldGameDev    schedule 02.02.2021    source источник
comment
Думайте о них как об адресах в памяти, на которые вы переходите.   -  person drum    schedule 02.02.2021
comment
@drum Так будут ли работать оба лейбла?   -  person NewOldGameDev    schedule 02.02.2021
comment
Метка — это просто имя места в вашей программе. Метки используются только во время сборки и не генерируют никакого кода. Они ничего не «содержат» и никак не «исполняют».   -  person fuz    schedule 02.02.2021
comment
@fuz о, я ассоциировал их с функцией, как в c   -  person NewOldGameDev    schedule 02.02.2021
comment
Функция в ассемблере обычно начинается с метки, так что вы можете обратиться к функции по ее имени вместо того, чтобы самостоятельно вычислять адрес. Но опять же, это просто имя, которое вы назначаете определенному месту, что-то вроде закладки в вашей программе.   -  person Michael    schedule 02.02.2021
comment
рассматривайте их как именованные закладки или путевые точки :)   -  person H.Hasenack    schedule 02.02.2021


Ответы (2)


Метки - это адреса (и обратите внимание, что имена функций в языках высокого уровня в основном являются метками).

loop:
  nop
  nop
  jump loop

это позволяет вам писать код, который имеет две функции. Во-первых, каков адрес цикла, 0x12345 или 0x8000 и т. д. Во-вторых, если моя инструкция псевдокода, установленная здесь, инструкция перехода работает с фиксированными адресами, поэтому для полного кодирования нужно знать 0x12345 или 0x8000. Инструкция или это относительно, где без меток программисту пришлось бы считать байты инструкции. Если бы nops были одним байтом каждый, а сам переход относителен, и, скажем, три байта, а смещение pc относительно конца инструкции, тогда вам нужно было бы сказать jump -5 в вашем коде, тогда, если вы добавили или удалили инструкции в loop вам придется пересчитывать смещения прыжка без ошибок.

Другой случай, который снова касается адреса, относится к внешним ссылкам:

fun:
  call more_fun
  ...

Если вы находитесь в наше время, когда вы можете сделать более одного файла исходного кода объектами, а затем связать их. (некоторые инструменты все еще поддерживают это, это было более распространено, когда я начал иметь один ассемблерный файл с .org и т. Д., И никаких внешних ссылок, только прямые и обратные ссылки). Затем вы можете иметь внешние ссылки, независимо от того, использует ли набор инструкций абсолютная или относительная адресация, чтобы завершить создание машинного кода для этого вызова, этот адрес необходимо разрешить. Таким образом, использование метки значительно упрощает работу программиста, и, как и в случае с локальными ссылками, инструменты могут вычислить все эти смещения или адреса для вас.

Редактировать

.thumb

    nop
    nop
    nop
loop:
    nop
    nop
    nop
    b loop
    
Disassembly of section .text:

00000000 <loop-0x6>:
   0:   46c0        nop         ; (mov r8, r8)
   2:   46c0        nop         ; (mov r8, r8)
   4:   46c0        nop         ; (mov r8, r8)

00000006 <loop>:
   6:   46c0        nop         ; (mov r8, r8)
   8:   46c0        nop         ; (mov r8, r8)
   a:   46c0        nop         ; (mov r8, r8)
   c:   e7fb        b.n 6 <loop>

поэтому второй столбец чисел (оба столбца в шестнадцатеричном формате) — это машинный код. Вы можете видеть, что на этикетке нет машинного кода, это просто этикетка, маркировка на коробке, она описывает вещь на коробке, а не содержимое своей коробки.

И я просто скажу вам, что ветвь к циклу, кодирующему младшие биты, является смещением, и в этом значении много единиц, потому что это отрицательное число (обратная ветвь относительно ПК).

Указанные выше адреса не связаны.

Один файл:

.thumb
    nop
    nop
loop:
    bl more_fun
    b loop

Другой:

.thumb
.thumb_func
.globl more_fun
more_fun:
    bx lr

unlinked мы видим, что дизассемблированный вызов (ссылка ветвления bl в этом наборе инструкций) имеет в основном заполнитель для смещения.

Disassembly of section .text:

00000000 <loop-0x4>:
   0:   46c0        nop         ; (mov r8, r8)
   2:   46c0        nop         ; (mov r8, r8)

00000004 <loop>:
   4:   f7ff fffe   bl  0 <more_fun>
   8:   e7fc        b.n 4 <loop>

когда-то связанный

Disassembly of section .text:

00001000 <loop-0x4>:
    1000:   46c0        nop         ; (mov r8, r8)
    1002:   46c0        nop         ; (mov r8, r8)

00001004 <loop>:
    1004:   f000 f801   bl  100a <more_fun>
    1008:   e7fc        b.n 1004 <loop>

0000100a <more_fun>:
    100a:   4770        bx  lr

инструкция bl изменена, чтобы иметь относительное смещение pc.

Всю эту магию делают инструменты, и нам нужно только следить за метками. Это то же самое для самих инструкций, которые мы можем использовать для чтения/записи человеком:

bx lr

вместо машинного кода:

0x4770

В наших программах.

person old_timer    schedule 02.02.2021

Метки не выполняются, это метаданные, которые позволяют вам ссылаться на это местоположение откуда-то еще. например в качестве цели ветки или для загрузки данных оттуда. Они не являются частью машинного кода, и процессоры о них не знают. Думайте о них как о маркерах нулевой ширины, которые позволяют вам ссылаться на эту позицию байта из другого места.

У них нет какой-либо неявной связи со следующими байтами или интервалом до следующей метки. Вы даже можете иметь несколько ярлыков в одном месте, если хотите. (Компиляторы могут делать это при автоматическом создании меток, например, в простой функции, тело которой сводится к простому циклу.

Выполнение просто провалится через метку, точно так же, как метка C goto внутри функции C. Или метка case 'x': внутри switch — помните, что вам нужен break, чтобы не провалиться к следующему делу.

Функции (и области действия) — это понятия высокого уровня. Метки (для определения символов) являются одним из инструментов, который asm предоставляет для реализации функций. (Вместе с такими инструкциями, как call и ret для перехода и сохранения обратного адреса.) В отличие от большой кучи спагетти-кода, который просто прыгает между произвольными точками, как gotos внутри одной огромной функции - по-видимому, это было типично в старые недобрые времена. до того, как сторонники структурного программирования указали, насколько проще было разрабатывать большие программы с точки зрения функций и блоков if/else, ограничивая способ использования переходов в ассемблере для согласования с этими концепциями. Функция не является первоклассной концепцией в чистом машинном коде или в большинстве языков ассемблера. (У MASM есть ключевое слово proc, которое вы можете использовать вместо метки.)


Для данных: в C массив типа static char foo[] = {1,2,3}; будет компилироваться примерно так:

 foo:
    .byte 0, 1, 2

Обратите внимание, что адрес метки имеет тот же адрес, что и первый элемент, а foo+1 — это адрес 2-го байта.

Но эквивалентно,

foo: .byte 0, 1
foo2: .byte 2
      .byte 3

Таким образом, вы помещаете метку в &foo[2], чтобы вы могли напрямую ссылаться на нее, если хотите, но вы могли бы также рассматривать весь диапазон байтов 0..3 как один массив. Это может быть более полезно для строк, где вы можете захотеть отдельно обратиться к суффиксу одной строки. например вместо отдельного .asciz "\n" вы можете просто вставить метку в новую строку в конце другой строки.


Вопросы и ответы по теме: примеры пропуска ярлыков

person Peter Cordes    schedule 05.02.2021