Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.07.2013, 17:21   #1
_PROGRAMM_
Участник клуба
 
Аватар для _PROGRAMM_
 
Регистрация: 30.07.2009
Сообщений: 1,603
По умолчанию Ближний и дальний вызов

Добрый день. Недавно я узнал, что NASM не определяет, какой произошел вызов: ближний или дальний. Я начал гулить, понял в чем суть, но так и не нашел примера из-за такого отношения:
Цитата:
Компилятор FASM автоматически определяет нужный тип машинной команды, поэтому в большинстве случаев не нужно об этом беспокоиться.
Мне, например, очень удобно, что NASM не запоминает размеры переменных, но какую выгоду я получу от его "склероза" к типам вызовов? Но это и не так важно. Мне теперь нужно понять, когда ставить retn, а когда retf. Я узнал, что ближний вызов, это когда процедура находится в одном сегменте с call, а дальний - в разных. Я бы не переживал, если бы не использовал asm с c++ вместе. Делаю я все таким образом
asm.asm
Код:
global AsmPrint:function
segment .data
str: db "Hello C++",0Ah,0
len equ $-str
segment .text

AsmPrint:
   mov rax,1
   mov rdi,1
   mov rsi,str
   mov rdx,len
   syscall
retn
main.cpp (сокращен, т.к. он содержит OpenGL, что совсем не нужно)
Код:
extern void AsmPrint();

int main(int argv, char * argc[])
{
    AsmPrint();                 //Вот она
    glutInit(&argv,argc);
    .........
    glutMainLoop();
    return 0;
}
собираем
Код:
nasm -felf64 asm.asm
g++ -c main.cpp 
g++ main.o asm.o -lGLU -lglut
В данном случает это будет дальний или ближний вызов?
Заранее спасибо

В мире нет вечных двигателей, зато есть вечные тормоза...

Блог

Последний раз редактировалось _PROGRAMM_; 16.07.2013 в 19:30.
_PROGRAMM_ вне форума Ответить с цитированием
Старый 16.07.2013, 17:29   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

сомневаюсь что линух плодит кучу сегментов для разных модулей приложения.
вообще проверить легко, так как если не тот тип возврата, то приложение улетит
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 16.07.2013, 19:31   #3
_PROGRAMM_
Участник клуба
 
Аватар для _PROGRAMM_
 
Регистрация: 30.07.2009
Сообщений: 1,603
По умолчанию

Цитата:
сомневаюсь что линух плодит кучу сегментов для разных модулей приложения.
А кто их плодит, зачем тогда дальний вызов?
Цитата:
так как если не тот тип возврата, то приложение улетит
А если я вызываю ее из разных сегментов?

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

Компилируя asm.asm я получаю объектный файл asm.o. C main.cpp все происходит точно так же (я в первом посте описал сборку). Выполняя третью команду я хватаю ошибку
Код:
main.o: In function `main':
main.cpp:(.text+0x287): undefined reference to `AsmPrint()'
collect2: error: ld returned 1 exit status
Ну, думаю, сейчас с помощью nm проверю. Результат:
nm asm.o
Код:
0000000000000000 T AsmPrint
0000000000000012 a len
0000000000000000 d str
nm main.o
Код:
                 U _Unwind_Resume
00000000000000d2 T _Z4Drawv
0000000000000251 T _Z5Timeri
0000000000000082 T _Z7KeyProchii
0000000000000000 T _Z7Reshapeii
                 U _Z8AsmPrintv
00000000000000b4 T _Z9KeyUpProchii
                 U __gxx_personality_v0
                 U exit
                 U glBegin
                 U glClear
                 U glClearColor
                 U glColor3f
                 U glEnd
                 U glLoadIdentity
                 U glMatrixMode
                 U glPopMatrix
                 U glPushMatrix
                 U glVertex2f
                 U glViewport
                 U gluOrtho2D
                 U glutDisplayFunc
                 U glutEnterGameMode
                 U glutGameModeString
                 U glutGet
                 U glutInit
                 U glutInitDisplayMode
                 U glutKeyboardFunc
                 U glutKeyboardUpFunc
                 U glutMainLoop
                 U glutPostRedisplay
                 U glutReshapeFunc
                 U glutSwapBuffers
                 U glutTimerFunc
0000000000000000 B keys
0000000000000277 T main
                 U sprintf
0000000000000000 D x1
0000000000000004 D x2
0000000000000100 B y1
0000000000000008 D y2
Перед AsmPrint стоит символ U это говорит о том, что функция описана вне объектного файла и будет находиться в другом, этот же символ стоит у функций gl, но есть одно существенное отличие - это названия. Их идентификаторы в коде и в объектном файле совпадают glBegin так и будет glBegin, а вот моя процедура имеет немного не свое имя _Z8AsmPrintv. Почему? Как исправить?

P.S. я когда переносил asm.asm в сообщение он был слегка изменен в ходе эксперимента. Функция называлась не _AsmPrint, а AsmPrint. Исправил. Результаты nm актуальны для исходников в первом посте.

Добавлено:
Изменил в asm исходнике с
Код:
global AsmPrint:function
segment .data
str: db "Hello C++",0Ah,0
len equ $-str
segment .text

AsmPrint:
   mov rax,1
   mov rdi,1
   mov rsi,str
   mov rdx,len
   syscall
retn
на
Код:
global _Z8AsmPrintv:function
segment .data
str: db "Hello C++",0Ah,0
len equ $-str
segment .text

_Z8AsmPrintv:
   mov rax,1
   mov rdi,1
   mov rsi,str
   mov rdx,len
   syscall
retn
И заработало! "Hello C++" на старте выводит. Вот только это не решение. Не хочу каждый раз в nm лезть. Смотрел объявление функций GL
Код:
GLAPI void GLAPIENTRY glVertex2f( GLfloat x, GLfloat y );
GLAPI = extern
т.к
Код:
#ifndef GLAPI
#define GLAPI extern
#endif

#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif

#ifndef APIENTRY
#define APIENTRY GLAPIENTRY
#endif

/* "P" suffix to be used for a pointer to a function */
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif

#ifndef GLAPIENTRYP
#define GLAPIENTRYP GLAPIENTRY *
#endif

#ifdef CENTERLINE_CLPP
#define signed
#endif
А GLAPIENTRY - не пойму. Как мне объявить функцию AsmPrint, чтобы она по-человечески выглядела в объектном файле?

В мире нет вечных двигателей, зато есть вечные тормоза...

Блог

Последний раз редактировалось _PROGRAMM_; 16.07.2013 в 19:59.
_PROGRAMM_ вне форума Ответить с цитированием
Старый 16.07.2013, 20:18   #4
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Дальний вызов нужен для того, чтоб менят сегмент. В современных ОС это в основном нужно самой ОС.

Процедуры в asm можно определять являются ли они near или far, соответствено будет генерится правильный ret и правильный call.

Прежде, чем писать на ассемблере, уясните понятие calling convention и name mangling - тогда многие вопросы отпадут.
waleri вне форума Ответить с цитированием
Старый 16.07.2013, 20:25   #5
_PROGRAMM_
Участник клуба
 
Аватар для _PROGRAMM_
 
Регистрация: 30.07.2009
Сообщений: 1,603
По умолчанию

Цитата:
Процедуры в asm можно определять являются ли они near или far, соответствено будет генерится правильный ret и правильный call.
А нельзя ли это сделать разностью адресов процедуры и места call?
Цитата:
Прежде, чем писать на ассемблере, уясните понятие calling convention и name mangling - тогда многие вопросы отпадут.
Буду штудировать, но сегодня уже не смогу, поэтому уточню, там есть решение разности имен? Неужели они зависят от соглашения вызова?

В мире нет вечных двигателей, зато есть вечные тормоза...

Блог
_PROGRAMM_ вне форума Ответить с цитированием
Старый 16.07.2013, 21:03   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
А нельзя ли это сделать разностью адресов процедуры и места call?
far и near отличаются содержимым стека, но ты не можешь определить что есть что в стеке, кроме тех случаев когда ты знаешь, что и сколько чего там лежит.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ближний ближнему Natali.ru Помощь студентам 9 18.01.2012 16:11
Дальний косвенный вызов Kenny McCormick Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 1 17.11.2010 00:59
CR-Team ищет программистов для проeкта "Дальний Свет" Ha3aP Фриланс 6 22.10.2009 19:28
Дальний рубеж треугольника Паскаля NecRomant Общие вопросы Delphi 3 05.11.2008 17:03
вызов Iceman Софт 7 24.02.2008 07:30