Страницы

Поиск по вопросам

Показаны сообщения с ярлыком boot. Показать все сообщения
Показаны сообщения с ярлыком boot. Показать все сообщения

пятница, 24 января 2020 г.

Как перенаправить вывод функции printf?

#c #boot


Выполняется код загрузчика операционной системы. Имеется только один процесс.
Как перенаправить вывод какой-либо сторонней функции на данном участке кода в буфер
char* (функция печатает в stdout с помощью printf, код этой функции я исправить не могу)? 

Команда, которая работает в консоли "> buffer", естественно, тут работать не будет,
да и файлов никаких нет... Код написан на чистом C, но могу написать костыль и на C++.

Подскажите пожалуйста, как решить проблему? Единственный способ, который я знал,
тут не будет работать.
    


Ответы

Ответ 1



Есть вариант решения через функцию freopen(), однако следует быть осторожнее в его использовании. char buffer[BUFSIZ]; freopen("/dev/null", "a", stdout); setbuf(stdout, buffer); // весь вывод через printf будет в буфер printf("simple print"); freopen("/dev/tty", "a", stdout); // возвращаем печать в stdout на консоль printf("%s\n", buffer); в Windows аналогом для /dev/null и /dev/tty служат NULL и CONOUT$ соответственно.

пятница, 10 января 2020 г.

Долгий запуск android приложения

#java #android #boot


Очень долго запускается приложение (в этом примере 40 секунд) если запуск происходит
впервые, потом запускается быстро.

Пробовал на простой активности (хотя есть и рабочие):

public class SplashActivity extends Activity {

    private static final String TAG = "SplashActivity";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "onResume");
        super.onResume();
    }
}


Проект состоит из двух рабочих модулей.

Модуль app:

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.android.support:design:23.2.0'
apt "org.androidannotations:androidannotations:$AAVersion"
compile "org.androidannotations:androidannotations-api:$AAVersion"
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.github.ParkSangGwon:TedPermission:v1.0.8'
compile 'com.vk:androidsdk:1.6.5'
compile 'com.fasterxml.jackson.core:jackson-core:2.4.1'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1'
compile project(':libw')
}


Модуль libw:

dependencies {
compile 'com.google.guava:guava:18.0'
compile 'com.android.support:support-v4:22.1.1'

compile 'com.google.http-client:google-http-client:1.19.0'
compile 'com.google.http-client:google-http-client-android:1.19.0'
compile 'com.google.http-client:google-http-client-jackson2:1.19.0'
compile 'com.google.oauth-client:google-oauth-client:1.19.0'
compile 'com.google.code.gson:gson:2.4'
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.google.protobuf:protobuf-java:2.6.1'

compile 'com.fasterxml.jackson.core:jackson-core:2.5.0'
compile('com.crashlytics.sdk.android:crashlytics:2.5.7@aar') {
    transitive = true;
}
compile files('libs/m3u8parser-0.2.jar')

jaxDoclet("com.google.doclava:doclava:1.0.5")
classpaths fileTree(dir: 'build/classes/release').matching { include 'io/x/sdk/S.java' }
}


Лог:

07-04 17:18:37.893 31219-31219/com.sapp W/System: ClassLoader referenced unknown
path: /data/app/com.sapp-1/lib/arm
07-04 17:19:17.429 31219-31219/com.sapp W/System: ClassLoader referenced unknown
path: /data/app/com.sapp-1/lib/arm
07-04 17:19:17.488 31219-31219/com.sapp D/SplashActivity: onCreate
07-04 17:19:17.513 31219-31219/com.sapp D/SplashActivity: onStart
07-04 17:19:17.513 31219-31219/com.sapp D/SplashActivity: onResume
07-04 17:19:17.522 31219-31875/com.sapp D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED:
false
07-04 17:19:17.539 31219-31219/com.sapp D/SplashActivity: onStart
07-04 17:19:17.539 31219-31219/com.sapp D/SplashActivity: onResume
07-04 17:19:17.558 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libEGL_mali.so
07-04 17:19:17.564 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libGLESv1_CM_mali.so
07-04 17:19:17.602 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libGLESv2_mali.so
[ 07-04 17:19:17.641 31219:31875 E/         ]
Device driver API match
Device driver API version: 29
User space API version: 29
[ 07-04 17:19:17.641 31219:31875 E/         ]
mali: REVISION=Linux-r3p2-01rel3 BUILD_DATE=Tue Jul 22 19:59:34 KST 2014
07-04 17:19:17.642 31219-31875/com.sapp I/OpenGLRenderer: Initialized EGL, version 1.4


В период долгого запуска приложения, в профайлере такая картина:


В период долгой загрузки приложения, на устройстве такая ситуация:


Это на экране можно видеть до появления в логе onResume, после чего отображается
экран загрузки.

Тестировал на Api 21, 23. 

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


Ответы

Ответ 1



Это особенности работы виртуальной машины ART. На самом деле, долгая загрузка кажется долгой изза оптимизации приложения после его установки. То есть, дивайсу нужно время не на запуск приложения, а на его распаковку. Соответственно, пока приложение не распакуется, оно не сможет запуститься. Проверить мою теорию вы можете удалив приложение, установив APK файл, подождав ~40 сек, и запустив приложение.

четверг, 2 января 2020 г.

Загрузка ядра linux

#linux #загрузка #kernel #boot


Здраствуйте, решил себе ради интереса создать linux дистрибутив.

Собрал ядро, создал загрузочный ramdisk, сделал все что мне нужно в ramdisk

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

Папка boot в ней две папки, первая initrd, вторая kernel, в первой лежит main.gz
во второй kernel.lk

Как теперь из этого всего сделать img образ чтоб запустить в эмуляторе? Гугл сказал
что мне нужен загрузчик

Много чего в гугле читал но нормального мануала по установке загрузчика для новичка
не нашел.

Мог бы кто расказать подробнее, 
ибо я новичок: первый раз собрал ядро.
    


Ответы

Ответ 1



Смотря какой эмулятор используете, например Qemu поддерживает прямую загрузку ядра и рамдиска. Используй параметры -kernel bzImage use 'bzImage' as kernel image -append cmdline use 'cmdline' as kernel command line -initrd file use 'file' as initial ram disk или Воспользуйся virt-manager или virt-install - хорошие менеджеры для qemu. На других виртуалках можно воспользоваться GRUB или Syslinux. Для этого создайте образ диска dd if=/dev/zero of=newos.img bs=10M count=10. Потом создадим там раздел и файловую систему $ fdisk ./newos.img Welcome to fdisk (util-linux 2.26.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. На диске не удалось найти таблицу разделов. Created a new DOS disklabel with disk identifier 0xa17f7b6a. Команда (m для справки): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Номер раздела (1-4, default 1): 1 Первый сектор (2048-20479, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-20479, default 20479): Created a new partition 1 of type 'Linux' and of size 9 MiB. Команда (m для справки): w The partition table has been altered. Syncing disks. $ sudo partx -a ./newos.img $ sudo mkfs.ext4 /dev/loop0p1 Смонтируй луп и скопируй туда папочку /boot/ и установим туда grub: grub-install --boot-directory=КАТАЛОГ /dev/loop0 И можно отключить образ $ partx -d ./newos.img В некоторых деталях алгоритм установки скорее всего прийдется подкоректировать. И всеже рекомендую использовать qemu для игр с рамдиском ;)

воскресенье, 15 декабря 2019 г.

Неубиваемый Service Android (Boot,Foreground,Sticky)

#android #service #boot #notifications


В основные задачи программы входит выполнение методов в фоновом режиме, для чего
используется Android Services.

Необходимо запустить Service таким образом, чтобы после закрытия MainActivity сервис
оставался в рабочем состоянии и мог создавать уведомления, а также, в случае закрытия
системой или же перезагрузки, самостоятельно восстанавливался.

На данный момент основная проблема состоит в поддержании жизни в MyService после
закрытия пользовательского интерфейса.

AutoStart:

В AndroidManifest.xml были прописаны

 


 


        
            
        



В BootReceiver.java:

@Override
public void onReceive(Context context, Intent intent) {
    Intent serviceIntent = new Intent(context, MyService.class);
    context.startService(serviceIntent);
}


Service:

В AndroidManifest.xml прописано:





В MyService.java находится следующий код, за исключением некоторых частей (описаны
наиболее важные элементы, в которых могут находиться ошибки, не позволяющие решить
поставленную задачу):

public void onCreate() {
    super.onCreate();
    notificationManager = (NotificationManager)
    this.getSystemService(this.NOTIFICATION_SERVICE);
}


 

public int onStartCommand(Intent intent, int flags, int startId) {
    sendNotification("Service started", "Service", "started");
    return Service.START_STICKY;
}


 

public void sendNotification(String Ticker,String Title,String Text) {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.setAction(Intent.ACTION_MAIN);
    notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);

    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),
0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setContentIntent(contentIntent)
    .setOngoing(true)   //invulnerable
    .setTicker(Ticker)
    .setContentTitle(Title)
    .setContentText(Text)
    .setWhen(System.currentTimeMillis());

    Notification notification;
    if (android.os.Build.VERSION.SDK_INT<=15) {
        notification = builder.getNotification(); // API 15 and lower
    }else {
        notification = builder.build();
    }

    startForeground(DEFAULT_NOTIFICATION_ID,notification);


 

@Override
public IBinder onBind(Intent intent) {
    return new Binder();
}

@Override
public void onRebind(Intent intent) {
    super.onRebind(intent);
}

@Override
public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
}

@Override
public void onDestroy()
{
    //Removing any notifications
    notificationManager.cancel(DEFAULT_NOTIFICATION_ID);

    //Disabling service
    stopSelf();
    super.onDestroy();
}


Запускается MyService из MainActivity следующим образом:

Intent intentService;


 

@Override
protected void onCreate(Bundle savedInstanceState)
{
    intentService = new Intent(this,MyService.class);
}


 

public void runService() {
    boolean working = isMyServiceRunning(MyService.class);
    if (!working) {
        startService(intentService);
    } else {
        stopService(intentService);
    }
}


 

public boolean isMyServiceRunning(Class serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}


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


Ответы

Ответ 1



Для адекватной работы всех предъявленных к "бессмертному" сервису требований потребовалось деинсталлировать нерабочую версию с устройства, после чего загрузить свежую сборку. Вызвано это было, вероятнее всего, именно разрешениями. Построение своей программы я начал практически с нуля, поэтому после первой установки приложению было выдано недостаточное для реализации функций "бессмертного" сервиса количество разрешений. На данный момент приложением используется всего два разрешения: Notifications и Autostart. На эту мысль меня натолкнула полная работоспособность приложения на всех прочих устройствах. Я постараюсь отразить в этом ответе все элементы кода, необходимые для работы "бессмертного" сервиса. Android Manifest: MainActivity: public class MainActivity extends AppCompatActivity { Intent intentService; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); intentService = new Intent(this,MyService.class); } public void click_Service(View v) { if (!isMyServiceRunning(MyService.class)) { startService(intentService); } else { stopService(intentService); } } private boolean isMyServiceRunning(Class serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; } } MyService: public class MyService extends Service { private NotificationManager notificationManager; public static final int DEFAULT_NOTIFICATION_ID = 101; public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) this.getSystemService(this.NOTIFICATION_SERVICE); } public int onStartCommand(Intent intent, int flags, int startId) { //Send Foreground Notification sendNotification("Ticker","Title","Text"); //Task doTask(); //return Service.START_STICKY; return START_REDELIVER_INTENT; } //Send custom notification public void sendNotification(String Ticker,String Title,String Text) { //These three lines makes Notification to open main activity after clicking on it Intent notificationIntent = new Intent(this, MainActivity.class); notificationIntent.setAction(Intent.ACTION_MAIN); notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentIntent(contentIntent) .setOngoing(true) //Can't be swiped out .setSmallIcon(R.mipmap.ic_launcher) //.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.large)) // большая картинка .setTicker(Ticker) .setContentTitle(Title) //Заголовок .setContentText(Text) // Текст уведомления .setWhen(System.currentTimeMillis()); Notification notification; if (android.os.Build.VERSION.SDK_INT<=15) { notification = builder.getNotification(); // API-15 and lower }else{ notification = builder.build(); } startForeground(DEFAULT_NOTIFICATION_ID, notification); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); //Removing any notifications notificationManager.cancel(DEFAULT_NOTIFICATION_ID); //Disabling service stopSelf(); } } MyReceiver: public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent intentService = new Intent(context, MyService.class); context.startService(intentService); } } Таким образом, мы получаем сервис, который автоматически запускается после старта системы. Пользовательский интерфейс может быть вызван нажатием на уведомление, которое невозможно убрать из панели уведомлений. После открытия пользовательского интерфейса сервис может быть отключён или включён вручную нажатием на соответствующую кнопку. В случае закрытия приложения, включая свайп приложения из Recent Task Bar'а, сервис останется включённым и продолжит свою работу. Единственным возможным способом закончить работу MyService без использования пользовательского интерфейса является закрытие процесса Application при помощи Force Stop в списке приложений или же остановка самого процесса вручную в меню настроек системы.

воскресенье, 1 декабря 2019 г.

Программирование загрузочного сектора C

#c #ассемблер #gcc #boot


Разбираюсь с программированием загрузочного сектора. Делаю согласно этой статье.
Всё получалось до момента программирования вывода "Hello, World!" на языке C. Вот код,
который приводится в статье (собственно, я его просто копирую):

__asm__(".code16\n");
__asm__("jmpl $0x0000, $main\n");

void printString(const char* pStr) {
     while(*pStr) {
          __asm__ __volatile__ (
               "int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0007)
          );
          ++pStr;
     }
}

void main() {
     printString("Hello, World");
}


Компилирую, линкую и тд опять же согласно той статье:

gcc -c -g -Os -m32 -ffreestanding -Wall -Werror test.c -o test.o
ld -melf_i386 -static -Ttest.ld -nostdlib --nmagic -o test.elf test.o
objcopy -O binary test.elf test.bin
dd if=/dev/zero of=floppy.img bs=512 count=2880
dd if=test.bin of=floppy.img


На всякий случай приведу содержимое test.ld:

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.text);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xaa55);
    }
}


Запускаю bochs, но вместо того, чтобы напечатать "Hello, World", у меня выводится
только один символ "S".

Перенёс функцию в main:

__asm__(".code16\n");
__asm__("jmpl $0x0000, $main\n");
void main()
{
    char s[] = "Hello, World";
    char *str = s;
    while (*str)
    {
        __asm__ __volatile__ (
               "int $0x10" : : "a"(0x0e00 | *str), "b"(0x0007)
          );
        ++str;
    }
}


После этого он перестал выводить что-либо в принципе. Помогло исключение флага оптимизации
-Os. Вывод стал верным. Немного поэкспериментировав, я понял, что эта оптимизация "убивает"
цикл.

Однако, тот же самый код, но перенесённый в функцию, всё так же выводит символ "S".

Прошу помощи в решении этой проблемы. А так же, если возможно, разъяснения, почему
флаг оптимизации "убивает" цикл. Спасибо!

UPD.

Hex от test.bin:

66 EA 3A 7C 00 00 00 00 66 55 66 89 E5 EB 19 67 66 8B 45 08 67 66 0F B6 00 66 0F
BE C0 80 CC 0E CD 10 67 66 83 45 08 01 67 66 8B 45 08 67 66 0F B6 00 84 C0 75 D9 90
66 5D C3 66 55 66 89 E5 66 68 4F 7C 00 00 E8 C0 FF 66 83 C4 04 90 C9 C3 48 65 6C 6C
6F 2C 20 57 6F 72 6C 64 00 14 00 00 00 00 00 00 00 01 7A 52 00 01 7C 08 01 1B 0C 04
04 88 01 00 00 1C 00 00 00 1C 00 00 00 8C FF FF FF 32 00 00 00 00 42 0E 08 85 02 43
0D 05 6C C5 0C 04 04 00 00 1C 00 00 00 3C 00 00 00 9E FF FF FF 15 00 00 00 00 42 0E
08 85 02 43 0D 05 4F C5 0C 04 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 55 AA


Файл был получен из следующего исходника:

__asm__(".code16\n");
__asm__("jmpl $0x0000, $main\n");

void printString(const char* str)
{
    while (*str)
    {
        __asm__ __volatile__ (
               "int $0x10" : : "a"(0x0e00 | *str));
        ++str;
    }
}

void main()
{
    printString("Hello, World");
}


UPD.

Результат дизассемблирования файла test.elf:

% objdump -d test.elf

test.elf:     file format elf32-i386

Disassembly of section .text:

00007c00 :
    7c00:   66 ea 3a 7c 00 00       ljmpw  $0x0,$0x7c3a
    ...

00007c08 :
    7c08:   66 55                   push   %bp
    7c0a:   66 89 e5                mov    %sp,%bp
    7c0d:   eb 19                   jmp    7c28 
    7c0f:   67 66 8b 45 08          mov    0x8(%di),%ax
    7c14:   67 66 0f b6 00          movzbw (%bx,%si),%ax
    7c19:   66 0f be c0             movsbw %al,%ax
    7c1d:   80 cc 0e                or     $0xe,%ah
    7c20:   cd 10                   int    $0x10
    7c22:   67 66 83 45 08 01       addw   $0x1,0x8(%di)
    7c28:   67 66 8b 45 08          mov    0x8(%di),%ax
    7c2d:   67 66 0f b6 00          movzbw (%bx,%si),%ax
    7c32:   84 c0                   test   %al,%al
    7c34:   75 d9                   jne    7c0f 
    7c36:   90                      nop
    7c37:   66 5d                   pop    %bp
    7c39:   c3                      ret    

00007c3a 
: 7c3a: 66 55 push %bp 7c3c: 66 89 e5 mov %sp,%bp 7c3f: 66 68 4f 7c pushw $0x7c4f 7c43: 00 00 add %al,(%eax) 7c45: e8 c0 ff 66 83 call 83677c0a 7c4a: c4 04 90 les (%eax,%edx,4),%eax 7c4d: c9 leave 7c4e: c3 ret UPD. Вот дизассемблирование hiew как просессор видит программу: 7c00: 66EA3A7C00000000 jmpf 00000:07C3A 7c08: 6655 3push ebp 7c0A: 6689E5 mov ebp,esp 7c0D: EB19 jmps 000000028 --↓1 7c0F: 67668B4508 2mov eax,[ebp][8] 7c14: 67660FB600 movzx eax,b,[eax] 7c19: 660FBEC0 movsx eax,al 7c1D: 80CC0E or ah,00E 7c20: CD10 int 010 7c22: 676683450801 add d,[ebp][8],1 7c28: 67668B4508 1mov eax,[ebp][8] 7c2D: 67660FB600 movzx eax,b,[eax] 7c32: 84C0 test al,al 7c34: 75D9 jnz 00000000F --↑2 7c36: 90 nop 7c37: 665D pop ebp 7c39: C3 retn ; 7c3A: 6655 push ebp 7c3C: 6689E5 mov ebp,esp 7c3F: 66684F7C0000 push 000007C4F ;' |O' 7c45: E8C0FF call 000000008 --↑3 7c48: 6683C404 add esp,4 7c4C: 90 nop 7c4C: 90 nop 7c4D: C9 leave 7c4E: C3 retn ; 7c4F: 48 65 6C 6C 6F-2C 20 57 6F-72 6C 64 Hellow, World Методом тыка, заметил, что действительно указатель необходимо смещать. Для загрузочной области необходимо поместить код в первый сектор диска со смещением в 0x7C00 байт. Это я указываю в файле test.ld. Я попробовал вывести всё, что у меня идёт после. И в куче разнообразных символов затаился желаемый "Hello, World". При этом изменение кода влечёт изменение в смещении, но я почти уверен, что оно будет всегда больше 0x7C00. Осталось понять, как правильно отслеживать это смещение...


Ответы

Ответ 1



В случае написание загрузочного сектора - проверяйте дизассемблером что у вас вышло. Для линукса незнаю как, для винды hiew.exe - хороший дизассемблер. Не забывайте что на старте - процессор находится в 16-битном режиме команд и в 16-битном режиме адресации - это важно 1) при сборке бинарника 2) для понимания что происходит 3)при дизассемблировании. Анализ даного случая показал, что код "неправильно" собран то ли компилятором то ли линкером. Коды 66 - переход в режим 32-битной команды, и 67 - переход в 32-битную адресацию 7c22: 676683450801 add d,[ebp][8],1 7c28: 67668B4508 1mov eax,[ebp][8] 7c2D: 67660FB600 movzx eax,b,[eax] эти переходы должны напрягать. Их использовать можно (66), но с умом. 32-битную адресацию (67) лучше избегать вообще, вплоть до переключения в защищенный режим, но первичный загрузчик этого не делает. Как вывод - Если код не работает, хотя он проверен, а картинка не складывается - то проблема с опциями сборки. Конкретно в даном случае помогло поменять директиву code16 (она в новой версии gcc исчезла) на code16gcc. Указывать code16 или code16gcc зависит от версии GCC.

Как восстановить GRUB?

#linux #windows #grub #boot #dual_boot


Стоял Linux Mint и Windows 7.
Слетела винда.
Переустановил  Windows и затерся grub.  Можно ли без переустановки восстановить загрузочный
сектор для linux ?
    


Ответы

Ответ 1



Нужно загрузиться с LiveCD, далее смонтировать корневой раздел установленной Linux системы, например, в папку /mnt. Станем суперпользователем $ sudo su Узнаем какие Linux увидел разделы и файловые системы # fdisk -l /dev/sda # blkid # lsblk Монтирование корня # mount /dev/sda3 /mnt Где sda3 - раздел с корневой файловой системой установленного Linux. Если содержимое /boot было расположено в отдельном от корневой файловой системы разделе, его тоже необходимо монтировать. Но в начале конечно всегда монтируется корень, после уже файловая система с boot в /mnt/boot Необходимо, если после монтирования корня каталог /boot установленной системы пуст. Пример монтирования /boot. # mount /dev/sda4 /mnt/boot/ Потом выполнить монтирование виртуальных ФС # mount --bind /dev /mnt/dev # mount --bind /dev/pts /mnt/dev/pts # mount --bind /proc /mnt/proc # mount --bind /dev /mnt/dev # mount --bind /sys /mnt/sys Сменим текущий корень # chroot /mnt Вы окажетесь уже в вашей старой системе, после этого выполнить # grub-install # update-grub2 Выйдем из корня установленной системы # exit Первая команда установит загрузчик stage1 grub2 в MBR, вторая обновит список загрузки - выполнит поиск систем и добавит их в меню загрузки. Далее необходимо размонтировать все файловые системы в обратном порядке # umount /mnt/sys # umount /mnt/dev # umount /mnt/proc # umount /mnt/dev/pts # umount /mnt/dev # umount /mnt/ Далее выключите компьютер. Включите. Установите загрузку с жесткого диска. # reboot

Ответ 2



Это самый безопасный метод востановления GRUB. Для него не нужно chroot-окружение, даже не нужны блочные устройства из /dev. Пояснение: GRUB определяет жесткие диски, подсоединеные к интерфейсам SATA и IDE, как (hdномер устройства); нумерация начинается с нуля. Раздел определяется следующим номером после номера устройства. Примеры: (hd0) — 1-й жесткий диск целиком; (hd0,0) — 1-й раздел на 1-ом диске; (hd0,1) — 2-й раздел на 1-ом диске; и так далее. GRUB2 начинает нумеровать раздела с 1, а устройства по прежнему с нуля.* Внимание: GRUB позволяет получить эту и другую функциональность ещё до загрузки OS. Во избежания взлома надо установить глобальный пароль. Для получения дальнейших подробностей смотрите документацию к загрузчику. Порядок действий: Грузим GNU/Linux с CD или USB. Запускаем от root-а GRUB в режиме shell-оболочки: # grub Далее определяем как определено устойство grub-ом, для этого вводим следующую команду: если /boot — отдельная ФС: # find /grub/stage1; если нет: find /boot/grub/stage1. GRUB в ответ выведит раздел на котором этот файл. Он та и нужен для следующих манипуляций. Сказать GRUB'у где boot-раздел/каталог # root (номер_нужного_диска,номер_нужного_раздела) Пример: # root (hd0,0) Указать устройство для записи в MBR первого сектора: # setup (нужный_раздел) Пример: # setup (hd0) Всё сделано. GRUB настроил MBR на загрузку себя с нужного вам раздела. Выходим из GRUB: # quit

воскресенье, 7 июля 2019 г.

Как перенести файлы bootmgr и BOOTNXT?


Недавно купил ssd и установил Windows 10, не отформатировав старый HDD. Windows 10 сама активировалась (цифровая лицензия). Я не спец в этой области, но думаю, что bootmgr и BOOTNXT нельзя удалять, могу ли я перенести их на установленный ssd и как-то задать путь загрузки? Подскажите, как грамотно поступить в данном случае?


Ответ

Только вот все равно ssd зависим от hdd
Если не успели уже инсталлировать массу программ в систему, я бы рекомендовал переустановить Windows 10 на чистый SSD, предварительно убрав из системы старый HDD. Иначе есть шанс (особенно, если вы заходите в систему через учетную запись MS) слёта активации (возможно, с потерей баллов), придётся заново проходить эту процедуру.
Поскольку система уже активирована, она передала :D данные в MS, и, если прошло 3 дня, можете смело переинсталлировать её. Да, вы потеряете (точнее, приобретёте, но это вопрос семантики) баллы, но, возможно, успеете минимизировать их потери.

вторник, 19 марта 2019 г.

Как перенаправить вывод функции printf?

Выполняется код загрузчика операционной системы. Имеется только один процесс. Как перенаправить вывод какой-либо сторонней функции на данном участке кода в буфер char* (функция печатает в stdout с помощью printf, код этой функции я исправить не могу)?
Команда, которая работает в консоли "> buffer", естественно, тут работать не будет, да и файлов никаких нет... Код написан на чистом C, но могу написать костыль и на C++.
Подскажите пожалуйста, как решить проблему? Единственный способ, который я знал, тут не будет работать.


Ответ

Есть вариант решения через функцию freopen(), однако следует быть осторожнее в его использовании.
char buffer[BUFSIZ]; freopen("/dev/null", "a", stdout); setbuf(stdout, buffer); // весь вывод через printf будет в буфер printf("simple print"); freopen("/dev/tty", "a", stdout); // возвращаем печать в stdout на консоль printf("%s
", buffer);
в Windows аналогом для /dev/null и /dev/tty служат NULL и CONOUT$ соответственно.

четверг, 21 февраля 2019 г.

Долгий запуск android приложения

Очень долго запускается приложение (в этом примере 40 секунд) если запуск происходит впервые, потом запускается быстро.
Пробовал на простой активности (хотя есть и рабочие):
public class SplashActivity extends Activity {
private static final String TAG = "SplashActivity";
@Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); }
@Override public void onStart() { Log.d(TAG, "onStart"); super.onStart(); }
@Override public void onResume() { Log.d(TAG, "onResume"); super.onResume(); } }
Проект состоит из двух рабочих модулей.
Модуль app:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.android.support:design:23.2.0' apt "org.androidannotations:androidannotations:$AAVersion" compile "org.androidannotations:androidannotations-api:$AAVersion" testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.github.ParkSangGwon:TedPermission:v1.0.8' compile 'com.vk:androidsdk:1.6.5' compile 'com.fasterxml.jackson.core:jackson-core:2.4.1' compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.1' compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1' compile project(':libw') }
Модуль libw:
dependencies { compile 'com.google.guava:guava:18.0' compile 'com.android.support:support-v4:22.1.1'
compile 'com.google.http-client:google-http-client:1.19.0' compile 'com.google.http-client:google-http-client-android:1.19.0' compile 'com.google.http-client:google-http-client-jackson2:1.19.0' compile 'com.google.oauth-client:google-oauth-client:1.19.0' compile 'com.google.code.gson:gson:2.4' compile 'com.google.code.findbugs:jsr305:3.0.0' compile 'com.google.protobuf:protobuf-java:2.6.1'
compile 'com.fasterxml.jackson.core:jackson-core:2.5.0' compile('com.crashlytics.sdk.android:crashlytics:2.5.7@aar') { transitive = true; } compile files('libs/m3u8parser-0.2.jar')
jaxDoclet("com.google.doclava:doclava:1.0.5") classpaths fileTree(dir: 'build/classes/release').matching { include 'io/x/sdk/S.java' } }
Лог:
07-04 17:18:37.893 31219-31219/com.sapp W/System: ClassLoader referenced unknown path: /data/app/com.sapp-1/lib/arm 07-04 17:19:17.429 31219-31219/com.sapp W/System: ClassLoader referenced unknown path: /data/app/com.sapp-1/lib/arm 07-04 17:19:17.488 31219-31219/com.sapp D/SplashActivity: onCreate 07-04 17:19:17.513 31219-31219/com.sapp D/SplashActivity: onStart 07-04 17:19:17.513 31219-31219/com.sapp D/SplashActivity: onResume 07-04 17:19:17.522 31219-31875/com.sapp D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: false 07-04 17:19:17.539 31219-31219/com.sapp D/SplashActivity: onStart 07-04 17:19:17.539 31219-31219/com.sapp D/SplashActivity: onResume 07-04 17:19:17.558 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libEGL_mali.so 07-04 17:19:17.564 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libGLESv1_CM_mali.so 07-04 17:19:17.602 31219-31875/com.sapp D/libEGL: loaded /system/lib/egl/libGLESv2_mali.so [ 07-04 17:19:17.641 31219:31875 E/ ] Device driver API match Device driver API version: 29 User space API version: 29 [ 07-04 17:19:17.641 31219:31875 E/ ] mali: REVISION=Linux-r3p2-01rel3 BUILD_DATE=Tue Jul 22 19:59:34 KST 2014 07-04 17:19:17.642 31219-31875/com.sapp I/OpenGLRenderer: Initialized EGL, version 1.4
В период долгого запуска приложения, в профайлере такая картина:
В период долгой загрузки приложения, на устройстве такая ситуация:
Это на экране можно видеть до появления в логе onResume, после чего отображается экран загрузки.
Тестировал на Api 21, 23.
Насколько я понимаю, долго происходит первоначальная инициализация, и связана она с загрузкой дополнительных библиотек. Как можно это ускорить или хотя бы отложить, чтобы показать экран загрузки?


Ответ

Это особенности работы виртуальной машины ART. На самом деле, долгая загрузка кажется долгой изза оптимизации приложения после его установки. То есть, дивайсу нужно время не на запуск приложения, а на его распаковку. Соответственно, пока приложение не распакуется, оно не сможет запуститься. Проверить мою теорию вы можете удалив приложение, установив APK файл, подождав ~40 сек, и запустив приложение.

понедельник, 14 января 2019 г.

Загрузка ядра linux

Здраствуйте, решил себе ради интереса создать linux дистрибутив.
Собрал ядро, создал загрузочный ramdisk, сделал все что мне нужно в ramdisk
В итоге у меня вышла такая структура каталогов:
Папка boot в ней две папки, первая initrd, вторая kernel, в первой лежит main.gz во второй kernel.lk
Как теперь из этого всего сделать img образ чтоб запустить в эмуляторе? Гугл сказал что мне нужен загрузчик
Много чего в гугле читал но нормального мануала по установке загрузчика для новичка не нашел.
Мог бы кто расказать подробнее, ибо я новичок: первый раз собрал ядро.


Ответ

Смотря какой эмулятор используете, например Qemu поддерживает прямую загрузку ядра и рамдиска. Используй параметры
-kernel bzImage use 'bzImage' as kernel image -append cmdline use 'cmdline' as kernel command line -initrd file use 'file' as initial ram disk
или Воспользуйся virt-manager или virt-install - хорошие менеджеры для qemu.
На других виртуалках можно воспользоваться GRUB или Syslinux. Для этого создайте образ диска dd if=/dev/zero of=newos.img bs=10M count=10. Потом создадим там раздел и файловую систему
$ fdisk ./newos.img
Welcome to fdisk (util-linux 2.26.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command.
На диске не удалось найти таблицу разделов. Created a new DOS disklabel with disk identifier 0xa17f7b6a.
Команда (m для справки): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Номер раздела (1-4, default 1): 1 Первый сектор (2048-20479, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-20479, default 20479):
Created a new partition 1 of type 'Linux' and of size 9 MiB.
Команда (m для справки): w The partition table has been altered. Syncing disks. $ sudo partx -a ./newos.img $ sudo mkfs.ext4 /dev/loop0p1
Смонтируй луп и скопируй туда папочку /boot/ и установим туда grub: grub-install --boot-directory=КАТАЛОГ /dev/loop0
И можно отключить образ $ partx -d ./newos.img
В некоторых деталях алгоритм установки скорее всего прийдется подкоректировать. И всеже рекомендую использовать qemu для игр с рамдиском ;)

вторник, 9 октября 2018 г.

Как восстановить GRUB?

Стоял Linux Mint и Windows 7. Слетела винда. Переустановил Windows и затерся grub. Можно ли без переустановки восстановить загрузочный сектор для linux ?


Ответ

Нужно загрузиться с LiveCD, далее смонтировать корневой раздел установленной Linux системы, например, в папку /mnt
Станем суперпользователем
$ sudo su
Узнаем какие Linux увидел разделы и файловые системы
# fdisk -l /dev/sda # blkid # lsblk
Монтирование корня
# mount /dev/sda3 /mnt
Где sda3 - раздел с корневой файловой системой установленного Linux.
Если содержимое /boot было расположено в отдельном от корневой файловой системы разделе, его тоже необходимо монтировать. Но в начале конечно всегда монтируется корень, после уже файловая система с boot в /mnt/boot Необходимо, если после монтирования корня каталог /boot установленной системы пуст.
Пример монтирования /boot.
# mount /dev/sda4 /mnt/boot/
Потом выполнить монтирование виртуальных ФС
# mount --bind /dev /mnt/dev # mount --bind /dev/pts /mnt/dev/pts # mount --bind /proc /mnt/proc # mount --bind /dev /mnt/dev # mount --bind /sys /mnt/sys
Сменим текущий корень
# chroot /mnt
Вы окажетесь уже в вашей старой системе, после этого выполнить
# grub-install # update-grub2
Выйдем из корня установленной системы
# exit
Первая команда установит загрузчик stage1 grub2 в MBR, вторая обновит список загрузки - выполнит поиск систем и добавит их в меню загрузки.
Далее необходимо размонтировать все файловые системы в обратном порядке
# umount /mnt/sys # umount /mnt/dev # umount /mnt/proc # umount /mnt/dev/pts # umount /mnt/dev # umount /mnt/
Далее выключите компьютер. Включите. Установите загрузку с жесткого диска.
# reboot

пятница, 5 октября 2018 г.

Программирование загрузочного сектора C

Разбираюсь с программированием загрузочного сектора. Делаю согласно этой статье. Всё получалось до момента программирования вывода "Hello, World!" на языке C. Вот код, который приводится в статье (собственно, я его просто копирую):
__asm__(".code16
"); __asm__("jmpl $0x0000, $main
");
void printString(const char* pStr) { while(*pStr) { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0007) ); ++pStr; } }
void main() { printString("Hello, World"); }
Компилирую, линкую и тд опять же согласно той статье:
gcc -c -g -Os -m32 -ffreestanding -Wall -Werror test.c -o test.o ld -melf_i386 -static -Ttest.ld -nostdlib --nmagic -o test.elf test.o objcopy -O binary test.elf test.bin dd if=/dev/zero of=floppy.img bs=512 count=2880 dd if=test.bin of=floppy.img
На всякий случай приведу содержимое test.ld:
ENTRY(main); SECTIONS { . = 0x7C00; .text : AT(0x7C00) { *(.text); } .sig : AT(0x7DFE) { SHORT(0xaa55); } }
Запускаю bochs, но вместо того, чтобы напечатать "Hello, World", у меня выводится только один символ "S".
Перенёс функцию в main:
__asm__(".code16
"); __asm__("jmpl $0x0000, $main
"); void main() { char s[] = "Hello, World"; char *str = s; while (*str) { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0e00 | *str), "b"(0x0007) ); ++str; } }
После этого он перестал выводить что-либо в принципе. Помогло исключение флага оптимизации -Os. Вывод стал верным. Немного поэкспериментировав, я понял, что эта оптимизация "убивает" цикл.
Однако, тот же самый код, но перенесённый в функцию, всё так же выводит символ "S".
Прошу помощи в решении этой проблемы. А так же, если возможно, разъяснения, почему флаг оптимизации "убивает" цикл. Спасибо!
UPD.
Hex от test.bin:
66 EA 3A 7C 00 00 00 00 66 55 66 89 E5 EB 19 67 66 8B 45 08 67 66 0F B6 00 66 0F BE C0 80 CC 0E CD 10 67 66 83 45 08 01 67 66 8B 45 08 67 66 0F B6 00 84 C0 75 D9 90 66 5D C3 66 55 66 89 E5 66 68 4F 7C 00 00 E8 C0 FF 66 83 C4 04 90 C9 C3 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 00 14 00 00 00 00 00 00 00 01 7A 52 00 01 7C 08 01 1B 0C 04 04 88 01 00 00 1C 00 00 00 1C 00 00 00 8C FF FF FF 32 00 00 00 00 42 0E 08 85 02 43 0D 05 6C C5 0C 04 04 00 00 1C 00 00 00 3C 00 00 00 9E FF FF FF 15 00 00 00 00 42 0E 08 85 02 43 0D 05 4F C5 0C 04 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
Файл был получен из следующего исходника:
__asm__(".code16
"); __asm__("jmpl $0x0000, $main
");
void printString(const char* str) { while (*str) { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0e00 | *str)); ++str; } }
void main() { printString("Hello, World"); }
UPD.
Результат дизассемблирования файла test.elf:
% objdump -d test.elf
test.elf: file format elf32-i386
Disassembly of section .text:
00007c00 : 7c00: 66 ea 3a 7c 00 00 ljmpw $0x0,$0x7c3a ...
00007c08 : 7c08: 66 55 push %bp 7c0a: 66 89 e5 mov %sp,%bp 7c0d: eb 19 jmp 7c28 7c0f: 67 66 8b 45 08 mov 0x8(%di),%ax 7c14: 67 66 0f b6 00 movzbw (%bx,%si),%ax 7c19: 66 0f be c0 movsbw %al,%ax 7c1d: 80 cc 0e or $0xe,%ah 7c20: cd 10 int $0x10 7c22: 67 66 83 45 08 01 addw $0x1,0x8(%di) 7c28: 67 66 8b 45 08 mov 0x8(%di),%ax 7c2d: 67 66 0f b6 00 movzbw (%bx,%si),%ax 7c32: 84 c0 test %al,%al 7c34: 75 d9 jne 7c0f 7c36: 90 nop 7c37: 66 5d pop %bp 7c39: c3 ret
00007c3a

: 7c3a: 66 55 push %bp 7c3c: 66 89 e5 mov %sp,%bp 7c3f: 66 68 4f 7c pushw $0x7c4f 7c43: 00 00 add %al,(%eax) 7c45: e8 c0 ff 66 83 call 83677c0a 7c4a: c4 04 90 les (%eax,%edx,4),%eax 7c4d: c9 leave 7c4e: c3 ret
UPD.
Вот дизассемблирование hiew как просессор видит программу:
7c00: 66EA3A7C00000000 jmpf 00000:07C3A 7c08: 6655 3push ebp 7c0A: 6689E5 mov ebp,esp 7c0D: EB19 jmps 000000028 --↓1 7c0F: 67668B4508 2mov eax,[ebp][8] 7c14: 67660FB600 movzx eax,b,[eax] 7c19: 660FBEC0 movsx eax,al 7c1D: 80CC0E or ah,00E 7c20: CD10 int 010 7c22: 676683450801 add d,[ebp][8],1 7c28: 67668B4508 1mov eax,[ebp][8] 7c2D: 67660FB600 movzx eax,b,[eax] 7c32: 84C0 test al,al 7c34: 75D9 jnz 00000000F --↑2 7c36: 90 nop 7c37: 665D pop ebp 7c39: C3 retn ; 7c3A: 6655 push ebp 7c3C: 6689E5 mov ebp,esp 7c3F: 66684F7C0000 push 000007C4F ;' |O' 7c45: E8C0FF call 000000008 --↑3 7c48: 6683C404 add esp,4 7c4C: 90 nop 7c4C: 90 nop 7c4D: C9 leave 7c4E: C3 retn ; 7c4F: 48 65 6C 6C 6F-2C 20 57 6F-72 6C 64 Hellow, World
Методом тыка, заметил, что действительно указатель необходимо смещать. Для загрузочной области необходимо поместить код в первый сектор диска со смещением в 0x7C00 байт. Это я указываю в файле test.ld. Я попробовал вывести всё, что у меня идёт после. И в куче разнообразных символов затаился желаемый "Hello, World". При этом изменение кода влечёт изменение в смещении, но я почти уверен, что оно будет всегда больше 0x7C00. Осталось понять, как правильно отслеживать это смещение...


Ответ

В случае написание загрузочного сектора - проверяйте дизассемблером что у вас вышло. Для линукса незнаю как, для винды hiew.exe - хороший дизассемблер. Не забывайте что на старте - процессор находится в 16-битном режиме команд и в 16-битном режиме адресации - это важно 1) при сборке бинарника 2) для понимания что происходит 3)при дизассемблировании.
Анализ даного случая показал, что код "неправильно" собран то ли компилятором то ли линкером. Коды 66 - переход в режим 32-битной команды, и 67 - переход в 32-битную адресацию
7c22: 676683450801 add d,[ebp][8],1 7c28: 67668B4508 1mov eax,[ebp][8] 7c2D: 67660FB600 movzx eax,b,[eax]
эти переходы должны напрягать. Их использовать можно (66), но с умом. 32-битную адресацию (67) лучше избегать вообще, вплоть до переключения в защищенный режим, но первичный загрузчик этого не делает. Как вывод - Если код не работает, хотя он проверен, а картинка не складывается - то проблема с опциями сборки.
Конкретно в даном случае помогло поменять директиву code16 (она в новой версии gcc исчезла) на code16gcc. Указывать code16 или code16gcc зависит от версии GCC.

четверг, 4 октября 2018 г.

Картинка-лого в консоли Linux

Никак не могу нагуглить. Каким образом мне реализовать вывод картинки в консоль (fb)? В поиске обсуждают в основном просмотр картинок через fbi, а мне нужно именно вывести картинку в консоль так, чтобы она была там наравне с остальным выводом. Вот как этот пингвин. Попробовал что-то типа
cat image.bmp > /dev/fb0,
но получил артефакты вместо картинки -- формат, видно, не тот (картинка 16-битная). Или опять скажут, что вопрос не вопрос?


Ответ

Нашёл следующее решение.
Сначала надо узнать формат буфера. У многих, в том числе и у меня, это BGRA, т.е. 4 байта на пиксел и в порядке: синий, зелёный, красный, пустой.
fbset -i выдаёт размеры экрана и ширину скан-строки в видеопамяти в байтах в строке "LineLength", может отличаться от ширины экрана * 4 в большую сторону. Делим это число на 4 -- получаем ширину картинки, которую надо подготовить.
Рисуем картинку в GIMPе -- ширина как посчитали, высота может быть любая, включаем альфа-канал. С помощью инструмента Цвет-Компоненты-Микшер каналов меняем местами красный и синий цвета. Сохраняем в "стандартном" формате "RAW".
Теперь её можно записывать во фреймбуфер с помощью cat
Недостаток который я не знаю как устранить: Драйвер текстовой консоли ничего знать не хочет о том, что вы там делаете с видеопамятью напрямую и считает, что там остались те буквы, что он там нарисовал последний раз, поэтому, при скроллировании, он не будет перерисовывать те места, где буквы по его мнению не должны измениться. Картинка не скроллируется и при переключении виртуальных консолей стирается.

Картинка-лого в консоли Linux

Никак не могу нагуглить. Каким образом мне реализовать вывод картинки в консоль (fb)? В поиске обсуждают в основном просмотр картинок через fbi, а мне нужно именно вывести картинку в консоль так, чтобы она была там наравне с остальным выводом. Вот как этот пингвин. Попробовал что-то типа
cat image.bmp > /dev/fb0,
но получил артефакты вместо картинки -- формат, видно, не тот (картинка 16-битная). Или опять скажут, что вопрос не вопрос?


Ответ

Нашёл следующее решение.
Сначала надо узнать формат буфера. У многих, в том числе и у меня, это BGRA, т.е. 4 байта на пиксел и в порядке: синий, зелёный, красный, пустой.
fbset -i выдаёт размеры экрана и ширину скан-строки в видеопамяти в байтах в строке "LineLength", может отличаться от ширины экрана * 4 в большую сторону. Делим это число на 4 -- получаем ширину картинки, которую надо подготовить.
Рисуем картинку в GIMPе -- ширина как посчитали, высота может быть любая, включаем альфа-канал. С помощью инструмента Цвет-Компоненты-Микшер каналов меняем местами красный и синий цвета. Сохраняем в "стандартном" формате "RAW".
Теперь её можно записывать во фреймбуфер с помощью cat
Недостаток который я не знаю как устранить: Драйвер текстовой консоли ничего знать не хочет о том, что вы там делаете с видеопамятью напрямую и считает, что там остались те буквы, что он там нарисовал последний раз, поэтому, при скроллировании, он не будет перерисовывать те места, где буквы по его мнению не должны измениться. Картинка не скроллируется и при переключении виртуальных консолей стирается.