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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 03.11.2022, 16:52   #1
D*V*L
Новичок
Джуниор
 
Регистрация: 03.11.2022
Сообщений: 4
По умолчанию Перенос кода с Linux x86_32 на Linux x86_64

Всем привет.
Хотел бы попросить помощи.
Имеется простенький компилятор, компилирующий программу "Hello World" под Linux x86_32. Создающийся elf работает корректно. Я решил переписать компилятор для генерации elf для Linux x86_64 - поправил структуру заголовков, сведений о динамической компоновке (для загрузки разделяемых библиотек использую релокацию R_X86_64_PC32). Дизассемблировал полученный код в IDA - ошибок не выдает, все вроде корректно.
Но при попытке запуска полученного elf выдает ошибку: "Symbol `printf' causes overflow in R_X86_64_PC32 relocation". Полагаю, ошибка в самом сгенерированном коде (в используемых регистрах? ):

Код:
sub_4001D9      proc near
                        push    rbp
                        mov     ebp, esp
                        sub      esp, 0
                        sub      esp, 4
                        mov     eax, offset aHelloWorld ; "Hello world!\n"
                        call      printf
                        add      esp, 4
                        mov     eax, 0
                        jmp      $+5

locret_400205:
                        leave
                        retn
sub_4001D9     endp
Подскажите, насколько сгенерированное корректно и как можно было бы исправить?

Последний раз редактировалось D*V*L; 03.11.2022 в 16:57.
D*V*L вне форума Ответить с цитированием
Старый 03.11.2022, 17:32   #2
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

А почему вы используете R_X86_64_PC32, а не R_X86_64_64. Вот и ошибка у вас из-за того, что невозможно записать 64-битный адрес в 32-битную переменную.

Может быть вы у себя и объявили ее как 64-битную, но загрузчику даете понять, что она у вас 32-битная (переменная printf в которую будет помещен адрес функции).

https://www.intezer.com/blog/malware...3-relocations/

Последний раз редактировалось macomics; 03.11.2022 в 17:42.
macomics вне форума Ответить с цитированием
Старый 03.11.2022, 17:51   #3
D*V*L
Новичок
Джуниор
 
Регистрация: 03.11.2022
Сообщений: 4
По умолчанию

Потому что, насколько я понимаю, R_X86_64_64 - это для константных значений, а не для функций. Разве нет?
Просто я пробовал и R_X86_64_64, и R_X86_64_PC64. Во втором случае IDA ругается, что используются нестандартные параметры релокации.

Скорее всего вы правы, но тогда не подскажите, что в таком случае указывать в этой структуре:
Elf64_Rela <4001F5h, 100000001h, 0>
?
(до того у меня было Elf64_Rela <4001F5h, 100000002h, 0FFFFFFFCh> - так валидирует корректно)

Последний раз редактировалось D*V*L; 03.11.2022 в 18:12.
D*V*L вне форума Ответить с цитированием
Старый 03.11.2022, 17:58   #4
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Нет. R_X86_64_64 это для релокаций с 64-битным IP, а для процессоров, у которых команды вызовов используют 32-битные адреса функций в 64-битном коде R_X86_64_PC32 (PC это тоже самое, что и IP).

У меня есть вот такое описание этой конструкции от FASM (можно найти в стандартных примерах вот тут)

Код:
; Elf64_Rela name, counter, R_X86_64_64;, 0
; name - указатель на переменную, для которой выполняется релокация
; counter - порядковый номер (начинается с 0, но 0 элемент зарезервирован)
; R_X86_64_64 - константа

macro Elf64_Rela offset,symbol,type,addend
{
  dq offset+0 ; = name
  dq (symbol+0) shl 32 + (type+0) ; = (counter shl 32) + R_X86_64_64
  dq addend+0 ; = 0
}

Последний раз редактировалось macomics; 03.11.2022 в 18:53.
macomics вне форума Ответить с цитированием
Старый 03.11.2022, 18:11   #5
D*V*L
Новичок
Джуниор
 
Регистрация: 03.11.2022
Сообщений: 4
По умолчанию

Цитата:
А почему у вас 2 параметр больше 32-бит?
Потому что в Elf64_Rela все три поля 64-битные. Суммарно 24 байта.

Например, при дизассемблировании кода, скомпилированного TCC (используется другая схема релокации):
Elf64_Rela <8049560h, 200000007h, 0> ; R_X86_64_JUMP_SLOT printf

PS Заметил, что в посте выше ошибся в названии релокации, с которой у меня выскакивала ошибка - правильно R_X86_64_PC64

Последний раз редактировалось D*V*L; 03.11.2022 в 18:14.
D*V*L вне форума Ответить с цитированием
Старый 03.11.2022, 18:47   #6
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Если вы используете R_X86_64_PC32 или R_X86_64_PC64, тогда у вас будет записан относительный адрес в переменную, а вам нужен абсолютный, чтобы выполнить call printf. Это обеспечивает константа R_X86_64_64. См. ссылку выше на описания.
macomics вне форума Ответить с цитированием
Старый 03.11.2022, 19:16   #7
D*V*L
Новичок
Джуниор
 
Регистрация: 03.11.2022
Сообщений: 4
По умолчанию

Проблема в том, что при использовании
Elf64_Rela <4001F5h, 100000001h, 0> ; R_X86_64_64 printf
вызов printf в дизассемблированном коде начинает выглядеть так:
call near ptr printf+4001F9h
(4001F9h - это адрес следующей за данной инструкции).

А если
Elf64_Rela <4001F5h, 100000001h, 0FFFFFFFCh> ; R_X86_64_64 printf+0FFFFFFFCh
то
call near ptr printf+4001F5h
(4001F5h - это адрес вот этого вот printf в данной строке).

Я там уже какие только комбинации не перебирал. )))

К слову сказать, для Linux x86_32 использовался тип релокации R_386_PC32 - там нормально работает.
D*V*L вне форума Ответить с цитированием
Старый 03.11.2022, 19:24   #8
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

А можно увидеть весь исходник? Чтобы не гадать где у вас проблемы только по одному кусочку кода. К тому же тот кусок кода полон бесполезных инструкций.

Он может выглядеть так
Код:
sub_4001D9      proc near
                        enter    0, 0

; Вызов printf с одним параметром в x86_64
                        mov      rdi, offset aHelloWorld ; db "Hello world!\n", 0
                        call     printf
                        mov      rsp, rbp

;                       mov      eax, 0 ; Это вообще не понятно зачем. Пускай уже возвращает результат из printf
                        leave
                        retn
sub_4001D9     endp
ADD: Если посмотрите в архиве по второй ссылке, то там есть пример программы на fasm под Linux x64. Она как раз использует printf для печати сообщения.

Последний раз редактировалось macomics; 03.11.2022 в 19:34.
macomics вне форума Ответить с цитированием
Ответ


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

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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Перенос Windows-Linux, Ошибка initializing argument lollollollol Qt и кроссплатформенное программирование С/С++ 2 19.05.2015 05:21
Перенос программы с Delphi на Linux Crunkordie Общие вопросы Delphi 6 20.02.2015 18:53
Переделка программного кода СИ под Linux SKu_ALP Фриланс 0 16.05.2012 14:58
Перевод программного кода из Windows в Linux Lex07 Qt и кроссплатформенное программирование С/С++ 0 06.12.2011 09:48
linux, чьего кода повтыкать? nahuahl Общие вопросы C/C++ 5 01.08.2011 19:12