Evg |
СОДЕРЖАНИЕ
Что такое метка на низком уровне
Запись от Evg размещена 20.03.2014 в 14:40
Показов 14297
Комментарии 18
|
За основу взят данный пост: https://www.cyberforum.ru/asm-... ost5938013. Изначально предполагал более развёрнутое объяснение поместить там, но в очередной раз получилось много букв и решил выделить в блог, т.к. скорее всего что-то придётся исправлять, к тому же информация может оказаться полезной и для других. В этом смысле данную статью нельзя рассматривать как законченную статью. Скорее это просто рабочая страница из записной книжки с мыслями "чтобы не потерялось" Чтобы не вводить в заблуждение, сразу же оговариваю две вещи. Я НЕ считаю ассемблер языком программирования (прошу не путать понятия "язык" и "язык программирования" - это НЕ одно и то же). Под словом "метка" подразумевается НЕ метка языка программирования, а метка в понимании ассемблерного программирования. Все попытки начать спор на тему того, является ассемблер языком программирования или нет, буду удалять. Хотелось бы переносить все такие посты куда-нибудь в другое место, но технически такой возможности нет (во всяком случае у меня). Если кому-то очень хочется поспорить - на форуме есть специальный раздел для холиваров Те, кто программировал на ассемблере или ковырялся в бинарных файлах после компиляторов с языков высокого уровня, привыкли к тому, что метка является неким эквивалентом адреса. Но в общем случае это не так. Если посмотреть форматы бинарных файлов, принцип работы линкера или ассемблера, то можно увидеть, что у метки нету такого атрибута, как адрес. У метки есть атрибут value - целочисленное значение. В большинстве случаев это значение действительно совпадает с адресом чего-нибудь. Но в общем случае этоне обязательно так Следующий пример я компилировал на i386-linux, а потому синтаксис ассемблерного файла соответствующий. При перекладывании кода под другие системы ассемблерный файл нужно будет переписать под свой синтаксис. Возможно, что ещё и имя метки надо будет поменять, т.к., например, gcc от cygwin'а ко всем глобальным именам пририсовывает символ подчерка C /* Файл t.c */ #include <stdio.h> /* Конкретный тип нам не важен, т.к. мы здесь работаем только с адресом * внешней метки с именем "label" */ extern int label; int main (void) { printf ("&label = %p\n", &label); return 0; } Assembler # Файл t1.s .globl label label: .byte 0 Code $ gcc t.c t1.s $ ./a.out &label = 0x804840c Пока тут было всё более менее стандартно Теперь возьмём другой ассемблерный файл Assembler # Файл t2.s .globl label .set label, 0x11223344 Code $ gcc t.c t2.s $ ./a.out &label = 0x11223344 Давайте посмотрим, как в объектном файле в реальности представлена метка: C /* Файл t.c */ int a = 1; int b = 2; int c = 3; Code $ gcc t.c -c $ readelf --sections t.o ... [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [ 2] .data PROGBITS 00000000 000034 00000c 00 WA 0 0 4 ... $ readelf --symbols t.o ... Num: Value Size Type Bind Vis Ndx Name ... 7: 00000000 4 OBJECT GLOBAL DEFAULT 2 a 8: 00000004 4 OBJECT GLOBAL DEFAULT 2 b 9: 00000008 4 OBJECT GLOBAL DEFAULT 2 c ... $ objdump -s t.o ... Contents of section .data: <0000> 01000000 02000000 03000000 ... Теперь возьмём другой исходник Assembler # Файл t.s .globl a .set a, 0x11223344 .globl b .set b, 0x55667788 .globl c .set c, 0x99aabbcc Code $ gcc t.s -c $ readelf --symbols t.o ... Num: Value Size Type Bind Vis Ndx Name ... 4: 11223344 0 NOTYPE GLOBAL DEFAULT ABS a 5: 55667788 0 NOTYPE GLOBAL DEFAULT ABS b 6: 99aabbcc 0 NOTYPE GLOBAL DEFAULT ABS c ... Если взять два последних примера и прилинковать их к другим модулям, которые потребляют метки "a", "b" и "c", то для всех прочих потребителей оба варианта получения объектного файла t.o принципиально ничем не будут отличаться. Есть точка потребления метки, есть модуль, в котором описано определение метки. Просто в одном случае определение метки ассоциировано с некоторыми данными (т.е. value метки есть адрес точки внутри данных), а во втором случае определение метки есть просто число |
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 18
Комментарии
-
Evg,
по поводу того, что в ассемблере "нет таких понятий как переменная и массив"
Сообщение от Mikl___
Сообщение от Evg
Сообщение от Mikl___
Студентам обучающимся применению языка ассемблер в качестве практики предлагается писать программы, которые выполняют арифметические, логические, статистические и т.д. вычисления, в которые входят переменные и массивы (одно/двух/многомерные), и хотя с точки зрения компилятора данные (переменные и массивы) можно рассматривать как метки, но на этом основании, говорить о том, что "Нету никаких переменных или массивов" так же не стоит
Сообщение от Evg
Запись от Mikl___ размещена 22.03.2014 в 09:22
-
Переменная языка является меткой в ассемблере. Обратное неверно. В ассемблере нету понятия переменной или массива. Такие понятие есть только в голове программиста, который пишет программу. Т.е. он ТРАКТУЕТ кусок памяти, как переменную типа int16, массив из 10 элементов типа float32 и т.д.
Я не знаю, чего там преподают студентам. Скорее всего, расписывать через переменные понятнее и проще. А в качестве результата имеем тех, кто "выучил ассемблер", но по прежнему нифига не разбираются во внутренностях машины или хотя бы в бинарных файлахЗапись от Evg размещена 22.03.2014 в 11:54
-
Запись от taras atavin размещена 22.03.2014 в 12:59
-
Запись от Evg размещена 22.03.2014 в 13:21
-
Запись от programina размещена 22.03.2014 в 23:17
-
Да, именно эти. В терминах объектных файлов эти метки называют symbol (в русскоязычной терминологии часто называют "символьная ссылка"). Symbol - это та сущность, через которую работает линковка. Если ты будешь смотреть не объектный файл, а ассемблерный (выдача по -S), то основная масса символов на ассемблере выглядит как имя и двоеточие, что обычно называется "метка"Запись от Evg размещена 22.03.2014 в 23:26
-
q.cppC++int main() { int a = 7, b = 9; if(a < b) a += b; }
g++ -S q.cppPerl.file "q.cpp" .def ___main; .scl 2; .type 32; .endef .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp call ___main movl $7, 12(%esp) movl $9, 8(%esp) movl 12(%esp), %eax cmpl 8(%esp), %eax jge L2 movl 8(%esp), %eax addl %eax, 12(%esp) L2: movl $0, %eax leave ret
То есть L2: - это метка, _main: получается тоже метка? Интересно, что будет если в строчке jge L2 написать jge _main, а затем каким-нибудь образом скомпилировать этот файл с асемблером и запустить полученную программу.Запись от programina размещена 23.03.2014 в 01:17
-
Именно так
Сообщение от programina
"Каким-нибудь образом скомпилировать" можно, подав команду "g++ q.s", где q.s - это файл, полученный приказом "g++ -S q.cpp" и нужным образом отредактированный. Если поменять "jge L2" на "jge _main", то конкретно в данном случае ничего не будет, т.к. этот переход всё равно не исполнится (потому что 7 меньше 9), но если сделать a = 10, то при исполнении управление честно передастся на метку _main. А дальше скорее всего зациклится (я не знаю, что делается внутри библиотечной ___main)
Сообщение от programina
Внутри процессора нету ни переменных, ни процедур. Процессор тупо исполняет последовательность операций. Какую последовательность операций подсунули, такую и исполнит. До тех пор, пока не нарвётся на недопустимую операцию (в случае приложения это обращение по некорректному адресу, переход на несуществующий адрес и т.п.)Запись от Evg размещена 23.03.2014 в 01:44
-
Запись от programina размещена 23.03.2014 в 02:59
-
Запись от Mikl___ размещена 23.03.2014 в 04:05
-
[QUOTE=Evg;bt9021]В начале добавил абзац с уточнением, что есть "метка" в контексте данной статьи[/QUOTE]Ассемблерная метка - это тоже адресе, но уже не места именно в коде, а вообще любого места в программе, включая место, в котором с точки зрения программиста находится инициируемая с бинарника переменная.Запись от taras atavin размещена 23.03.2014 в 05:34
-
На верхнем уровне абстракции имеет смысл остановиться, если пишешь учебник. А у тебя ведь не учебник, а справочник. Или ты предполагал переписать его. Что-то уже из головы начало всё вылетать.
Сообщение от Mikl___
Ну а даже если и учебник. В учебниках всегда есть разделы для продвинутого изучения. Для тех, у кого голова работает, никогда не будет лишним описать истинную природу вещей. Просто мне казалось, что если и есть смысл писать свой учебник, то побудительным мотивом для этого должно быть желание написать не так, как у всех, а правильно и удобноЗапись от Evg размещена 23.03.2014 в 10:24
-
Запись от taras atavin размещена 23.03.2014 в 10:49
-
Бытовое понятие метки именно такое. Но в реальности, метка - это по сути дела целочисленное значение, которое совпадает с адресом. А может и не совпадать ни с чьим с адресом. А может. Метка - это то, что в конечном исполняемом коде будет заменено на число.
Сообщение от taras atavin
На бытовом уровне в %ebx мы записываем целочисленную константу, а в регистр %ebx - адрес переменной. Но с точки зрения машины эти два mov'а ничем не отличаются, т.к. записывают в регистр числа. Для связки ассемблер-линкер "A" и "B" являются просто числами. Просто значение числа A можно по простому получить ещё на этапе ассемблирования, а значения числа B можно получить (уже не по простому) на этапе линковки. Но итог будет одинаковый. То, что в ассемблерной программе было меткой, в итоговом коде будет заменено на число. Ибо метка - это всего лишь удобная форма записи, чтобы не оперировать конкретными числамиAssembler# максимальное количество очков A equ 0x100 # текущее количество очков B db 0x0 # записываем в %eax максимальное количество очков mov %eax, A # записываем в %ebx адрес ячейки с количеством текущих очков mov %ebx, B
Запись от Evg размещена 23.03.2014 в 11:08
-
Если есть желание - запусти из-под отладчика gdb и пошагово протрассируй, найдёшь, где упало. "Пошагово" - в смысле машинного кода, а не языка программирования. "nexti" - команда отладчика, которая выполняет одну инструкцию машины
Сообщение от programina
Ты можешь передать управление вообще на какую-нибудь глобальную переменную. Программа нормально скомпилируется. Но упадёт на исполнении, т.к. современные операционные системы имеют исполняемые страницы памяти, и неисполняемые. Всё это можно пролечить mprotect'омЗапись от Evg размещена 23.03.2014 в 11:13
-
Запись от Evg размещена 23.03.2014 в 11:16
-
Запись от Mikl___ размещена 24.03.2014 в 11:26
-
Запись от Evg размещена 24.03.2014 в 21:44



