C/C++

X11 matatás Xlib nélkül

Fórumok

Érdekes szösszenet, bár hasznát venni sosem fogom, de mégis lekötött, szerintem roppant tanulságos.

https://hereket.com/posts/from-scratch-x11-windowing/

Hogyan nyissunk X11 ablakot és írjuk rá, hogy "Helló világ", majd fogadjunk event-eket, mindössze 200 sornyi C kódból, bármiféle lib vagy header használata nélkül, csakis közvetlen socket írás / olvasással (POSIX headerök és libc azért kell neki, de semmi más).

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>


int32_t GlobalId = 0;
int32_t GlobalIdBase = 0;
int32_t GlobalIdMask = 0;
int32_t GlobalRootWindow = 0;
int32_t GlobalRootVisualId = 0;

int32_t GlobalTextOffsetX = 10;
int32_t GlobalTextOffsetY = 20;

#define READ_BUFFER_SIZE 16*1024

#define RESPONSE_STATE_FAILED 0
#define RESPONSE_STATE_SUCCESS 1
#define RESPONSE_STATE_AUTHENTICATE 2

#define X11_REQUEST_CREATE_WINDOW 1
#define X11_REQUEST_MAP_WINDOW 8
#define X11_REQUEST_IMAGE_TEXT_8 76
#define X11_REQUEST_OPEN_FONT 45
#define X11_REQUEST_CREATE_GC 55


#define X11_EVENT_FLAG_KEY_PRESS 0x00000001
#define X11_EVENT_FLAG_KEY_RELEASE 0x00000002
#define X11_EVENT_FLAG_EXPOSURE 0x8000


#define WINDOWCLASS_COPYFROMPARENT 0
#define WINDOWCLASS_INPUTOUTPUT 1
#define WINDOWCLASS_INPUTONLY 2

#define X11_FLAG_BACKGROUND_PIXEL 0x00000002 
#define X11_FLAG_WIN_EVENT 0x00000800 

#define X11_FLAG_FG 0x00000004
#define X11_FLAG_BG 0x00000008
#define X11_FLAG_FONT 0x00004000
#define X11_FLAG_GC_EXPOSURE 0x00010000

#define PAD(N) ((4 - (N % 4)) % 4)

void VerifyOrDie(int IsSuccess, const char *Message) {
    if(!IsSuccess)  {
        fprintf(stderr, "%s", Message);
        exit(13);
    }
}

void VerifyOrDieWidthErrno(int IsSuccess, const char *Message) {
    if(!IsSuccess)  {
        perror(Message);
        exit(13);
    }
}

void DumpResponseError(int Socket, char* ReadBuffer) {
        uint8_t ReasonLength = ReadBuffer[1];
        uint16_t MajorVersion = *((uint16_t*)&ReadBuffer[2]);
        uint16_t MinorVersion = *((uint16_t*)&ReadBuffer[4]);
        uint16_t AdditionalDataLength = *((uint16_t*)&ReadBuffer[6]); // Length in 4-byte units of "additional data"
        uint8_t *Message = (uint8_t*)&ReadBuffer[8];

        int BytesRead = read(Socket, ReadBuffer + 8, READ_BUFFER_SIZE-8);

        printf("State: %d\n", ReadBuffer[0]);
        printf("MajorVersion: %d\n", MajorVersion);
        printf("MinorVersion: %d\n", MinorVersion);
        printf("AdditionalDataLength: %d\n", AdditionalDataLength);
        printf("Reason: %s\n", Message);
}

void AuthenticateX11() {
    fprintf(stderr, "Current version of the app does not support authentication.\n");
    fprintf(stderr, "Please run 'xhost +local:' in your terminal to disable cookie based authentication\n");
    fprintf(stderr, "and allow local apps to communication with Xorg without it.");
}

int32_t GetNextId() {
    int32_t Result = (GlobalIdMask & GlobalId) | GlobalIdBase;
    GlobalId += 1;
    return Result;
}

void PrintResponseError(char *Data, int32_t Size) {
    char ErrorCode = Data[1];
    const char *ErrorNames[] = {
        "Unknown Error",
        "Request",
        "Value",
        "Window",
        "Pixmap",
        "Atom",
        "Cursor",
        "Font",
        "Match",
        "Drawable",
        "Access",
        "Alloc",
        "Colormap",
        "GContext",
        "IDChoice",
        "Name",
        "Length",
        "Implementation",
    };

    const char* ErrorName = "Unknown error";
    if(ErrorCode < sizeof(ErrorNames) / sizeof(ErrorNames[0])) {
        ErrorName = ErrorNames[ErrorCode];
    }

    
    uint16_t Minor = *((uint16_t*)&Data[8]);
    uint8_t Major = *((uint8_t*)&Data[10]);

    printf("\033[0;31m");
    printf("Response Error: [%d] %s", ErrorCode, ErrorName);
    printf("	Minor: %d, Major: %d", Minor, Major);
    printf("\033[0m\n");


}

void PrintAndProcessEvent(char *Data, int32_t Size) {
    char EventCode = Data[0];
    const char* EventNames[] = {
        "-- Wrong Event Code --",
        "-- Wrong Event Code --",
        "KeyPress",
        "KeyRelease",
        "ButtonPress",
        "ButtonRelease",
        "MotionNotify",
        "EnterNotify",
        "LeaveNotify",
        "FocusIn",
        "FocusOut",
        "KeymapNotify",
        "Expose",
        "GraphicsExposure",
        "NoExposure",
        "VisibilityNotify",
        "CreateNotify",
        "DestroyNotify",
        "UnmapNotify",
        "MapNotify",
        "MapRequest",
        "ReparentNotify",
        "ConfigureNotify",
        "ConfigureRequest",
        "GravityNotify",
        "ResizeRequest",
        "CirculateNotify",
        "CirculateRequest",
        "PropertyNotify",
        "SelectionClear",
        "SelectionRequest",
        "SelectionNotify",
        "ColormapNotify",
        "ClientMessage",
        "MappingNotify",
    };

#define REPLY_EVENT_CODE_KEY_PRESS 2
#define REPLY_EVENT_CODE_EXPOSE 12

const char* TERMINAL_TEXT_COLOR_RED = "\033[0;32m";
const char* TERMINAL_TEXT_COLOR_CLEAR = "\033[0m";

    if(EventCode == REPLY_EVENT_CODE_EXPOSE) {
        // NOTE: Exposure event
        const char *EventName = "Expose";
        uint16_t SequenceNumber = *((uint16_t*)&Data[2]);
        uint32_t Window = *((uint32_t*)&Data[4]);
        uint16_t X = *((uint16_t*)&Data[8]);
        uint16_t Y = *((uint16_t*)&Data[10]);
        uint16_t Width = *((uint16_t*)&Data[12]);
        uint16_t Height = *((uint16_t*)&Data[14]);
        uint16_t Count = *((uint16_t*)&Data[16]);

        printf(TERMINAL_TEXT_COLOR_RED);
            printf("%s: ", EventName);
        printf(TERMINAL_TEXT_COLOR_CLEAR);

        printf("Seq %d, ", SequenceNumber);
        printf("Win %d: ", Window);
        printf("X %d: ", X);
        printf("Y %d: ", Y);
        printf("Width %d: ", Width);
        printf("Height %d: ", Height);
        printf("Count %d: ", Count);
        printf("\n");
        /* printf("%s: Seq %d\n", EventName, SequenceNumber); */
    } else if(EventCode == REPLY_EVENT_CODE_KEY_PRESS) {
        const char *EventName = "KeyPress";
        char KeyCode = Data[1];
        uint16_t SequenceNumber = *((uint16_t*)&Data[2]);
        uint32_t TimeStamp = *((uint32_t*)&Data[4]);
        uint32_t RootWindow = *((uint32_t*)&Data[8]);
        uint32_t EventWindow = *((uint32_t*)&Data[12]);
        uint32_t ChildWindow = *((uint32_t*)&Data[16]); // NOTE: Always 0
        int16_t RootX = *((int16_t*)&Data[20]);
        int16_t RootY = *((int16_t*)&Data[22]);
        int16_t EventX = *((int16_t*)&Data[24]);
        int16_t EventY = *((int16_t*)&Data[26]);
        int16_t SetOfKeyButMask = *((int16_t*)&Data[28]);
        int8_t IsSameScreen = *((int8_t*)&Data[30]);

        printf(TERMINAL_TEXT_COLOR_RED);
            printf("%s: ", EventName);
        printf(TERMINAL_TEXT_COLOR_CLEAR);

        // NOTE: Temporary hack that will not work everywhere
        int StepSize = 10;
        if(KeyCode == 25) { GlobalTextOffsetY += StepSize; }
        if(KeyCode == 39) { GlobalTextOffsetY -= StepSize; }
        if(KeyCode == 38) { GlobalTextOffsetX -= StepSize; }
        if(KeyCode == 40) { GlobalTextOffsetX += StepSize; }

        printf("Code %u, ", (uint8_t)KeyCode);
        printf("Seq %d, ", SequenceNumber);
        printf("Time %d, ", TimeStamp);
        printf("Root %d, ", RootWindow);
        printf("EventW %d, ", EventWindow);
        printf("Child %d, ", ChildWindow);
        printf("RX %d, ", RootX);
        printf("RY %d, ", RootY);
        printf("EX %d, ", EventX);
        printf("EY %d, ", EventY);
        printf("\n");
    } else {
        const char* EventName = " - Unknown Event Code -";
        if(EventCode < sizeof(EventNames) / sizeof(EventNames[0])) {
            EventName = EventNames[EventCode];
        }
        // printf("-------------Event: %s\n", EventName);
        // for(int i = 0; i < Size; i++) {
            // printf("%c", Data[i]);
        // }
        // printf("\n");
    }

}

void GetAndProcessReply(int Socket) {
    char Buffer[1024] = {};
    int32_t BytesRead = read(Socket, Buffer, 1024);

    uint8_t Code = Buffer[0];

    if(Code == 0) {
        PrintResponseError(Buffer, BytesRead);
    } else if (Code == 1) {
        printf("---------------- Unexpected reply\n");
    } else {
        // NOTE: Event?
        PrintAndProcessEvent(Buffer, BytesRead);
    }
}

int X_InitiateConnection(int Socket) { 
    // TODO: Remove global variables and put them into 'connection' struct.
    int SetupStatus = 1;
    char SendBuffer[16*1024] = {};
    char ReadBuffer[16*1024] = {};

    uint8_t InitializationRequest[12] = {};
    InitializationRequest[0] = 'l';
    InitializationRequest[1] = 0;
    InitializationRequest[2] = 11;

    int BytesWritten = write(Socket, (char*)&InitializationRequest, sizeof(InitializationRequest));
    VerifyOrDie(BytesWritten == sizeof(InitializationRequest), "Wrong amount of bytes written during initialization");

    int BytesRead = read(Socket, ReadBuffer, 8);

    if(ReadBuffer[0] == RESPONSE_STATE_FAILED) {
        DumpResponseError(Socket, ReadBuffer);
    }
    else if(ReadBuffer[0] == RESPONSE_STATE_AUTHENTICATE) {
        AuthenticateX11();
    }
    else if(ReadBuffer[0] == RESPONSE_STATE_SUCCESS) {
        printf("INIT Response SUCCESS. BytesRead: %d\n", BytesRead);

        BytesRead = read(Socket, ReadBuffer + 8, READ_BUFFER_SIZE-8);
        printf("---------------------------%d\n", BytesRead);

        /* -------------------------------------------------------------------------------- */
        uint8_t _Unused = ReadBuffer[1];
        uint16_t MajorVersion = *((uint16_t*)&ReadBuffer[2]);
        uint16_t MinorVersion = *((uint16_t*)&ReadBuffer[4]);
        uint16_t AdditionalDataLength = *((uint16_t*)&ReadBuffer[6]); // Length in 4-byte units of "additional data"

        uint32_t ResourceIdBase = *((uint32_t*)&ReadBuffer[12]);
        uint32_t ResourceIdMask = *((uint32_t*)&ReadBuffer[16]);
        uint16_t LengthOfVendor = *((uint16_t*)&ReadBuffer[24]);
        uint8_t NumberOfFormants = *((uint16_t*)&ReadBuffer[29]);
        uint8_t *Vendor = (uint8_t *)&ReadBuffer[40];

        int32_t VendorPad = PAD(LengthOfVendor);
        int32_t FormatByteLength = 8 * NumberOfFormants;
        int32_t ScreensStartOffset = 40 + LengthOfVendor + VendorPad + FormatByteLength;

        uint32_t RootWindow = *((uint32_t*)&ReadBuffer[ScreensStartOffset]);
        uint32_t RootVisualId = *((uint32_t*)&ReadBuffer[ScreensStartOffset + 32]);

        GlobalIdBase = ResourceIdBase;
        GlobalIdMask = ResourceIdMask;
        GlobalRootWindow = RootWindow;
        GlobalRootVisualId = RootVisualId;

        SetupStatus = 0;
    }

    return SetupStatus;
}

int X_CreatWindow(int Socket, int X, int Y, int Width, int Height) {
    // TODO: Put this into 'connection' struct
    char SendBuffer[16*1024] = {};
    char ReadBuffer[16*1024] = {};

    int32_t WindowId = GetNextId();
    int32_t Depth = 0;
    uint32_t BorderWidth = 1;
    int32_t CreateWindowFlagCount = 2;
    int RequestLength = 8+CreateWindowFlagCount;

    SendBuffer[0] = X11_REQUEST_CREATE_WINDOW;
    SendBuffer[1] = Depth;
    *((int16_t *)&SendBuffer[2]) = RequestLength;
    *((int32_t *)&SendBuffer[4]) = WindowId;
    *((int32_t *)&SendBuffer[8]) = GlobalRootWindow;
    *((int16_t *)&SendBuffer[12]) = X;
    *((int16_t *)&SendBuffer[14]) = Y;
    *((int16_t *)&SendBuffer[16]) = Width;
    *((int16_t *)&SendBuffer[18]) = Height;
    *((int16_t *)&SendBuffer[20]) = BorderWidth;
    *((int16_t *)&SendBuffer[22]) = WINDOWCLASS_INPUTOUTPUT;
    *((int32_t *)&SendBuffer[24]) = GlobalRootVisualId;
    *((int32_t *)&SendBuffer[28]) = X11_FLAG_WIN_EVENT | X11_FLAG_BACKGROUND_PIXEL;
    *((int32_t *)&SendBuffer[32]) = 0xff000000;
    *((int32_t *)&SendBuffer[36]) = X11_EVENT_FLAG_EXPOSURE | X11_EVENT_FLAG_KEY_PRESS;

    int BytesWritten = write(Socket, (char *)&SendBuffer, RequestLength*4);

    return WindowId;
}

int X_MapWindow(int Socket, int WindowId) {
    // TODO: Put this into 'connection' struct
    char SendBuffer[16*1024] = {};
    char ReadBuffer[16*1024] = {};

    SendBuffer[0] = X11_REQUEST_MAP_WINDOW;
    SendBuffer[1] = 0;
    *((int16_t *)&SendBuffer[2]) = 2;
    *((int32_t *)&SendBuffer[4]) = WindowId;

    int BytesWritten = write(Socket, (char *)&SendBuffer, 2*4);
    return 0;
}

void X_OpenFont(int32_t Socket, char *FontName, int32_t FontId) {
    char SendBuffer[16*1024] = {};
    char ReadBuffer[16*1024] = {};
    int BytesWritten = 0;
    int BytesRead = 0;

    int32_t FontNameLength = strlen((char *)FontName);
    int32_t Pad = PAD(FontNameLength);
    int RequestLength = (3 + (FontNameLength + Pad)/4);

    SendBuffer[0] = X11_REQUEST_OPEN_FONT;
    SendBuffer[1] = 0;
    *((uint16_t *)&SendBuffer[2]) = RequestLength;
    *((uint32_t *)&SendBuffer[4]) = FontId;
    *((uint16_t *)&SendBuffer[8]) = FontNameLength;
    strncpy(SendBuffer + 12, (char *)FontName, FontNameLength);

    int32_t WriteSize = 12 + FontNameLength + Pad;
    BytesWritten = write(Socket, (char *)&SendBuffer, WriteSize);
}

void X_CreateGC(int32_t Socket, int32_t GcId, int32_t FontId) {
    char SendBuffer[16*1024] = {};

    int32_t CreateGcFlagCount = 3;
    int RequestLength = 4 + CreateGcFlagCount;

    SendBuffer[0] = X11_REQUEST_CREATE_GC;
    SendBuffer[1] = 0;
    *((int16_t *)&SendBuffer[2]) = RequestLength;
    *((int32_t *)&SendBuffer[4]) = GcId;
    *((int32_t *)&SendBuffer[8]) = GlobalRootWindow;
    *((int32_t *)&SendBuffer[12]) = X11_FLAG_FG | X11_FLAG_BG | X11_FLAG_FONT;
    *((int32_t *)&SendBuffer[16]) = 0xFF00FF00; // Foreground
    *((int32_t *)&SendBuffer[20]) = 0xFF000000; // Background
    *((int32_t *)&SendBuffer[24]) = FontId; // Font

    write(Socket, (char *)&SendBuffer, RequestLength*4);
}

void WriteText(int Socket, int WindowId, int GCid, int16_t X, int16_t Y, const char *Text, int32_t TextLength) {
    char Buffer[16*1024] = {};

    uint32_t ContentLength = 4 + (TextLength + PAD(TextLength))/4;

    Buffer[0] = (uint8_t)X11_REQUEST_IMAGE_TEXT_8;
    Buffer[1] = TextLength;
    *((int16_t *)&Buffer[2]) = ContentLength; 
    *((int32_t *)&Buffer[4]) = WindowId;
    *((int32_t *)&Buffer[8]) = GCid;
    *((int16_t *)&Buffer[12]) = X; 
    *((int16_t *)&Buffer[14]) = Y; 

    strncpy(&Buffer[16], (char *)Text, TextLength);
    int BytesWritten = write(Socket, (char *)&Buffer, ContentLength*4);
}

int main(){
    int Socket = socket(AF_UNIX, SOCK_STREAM, 0);
    VerifyOrDie(Socket > 0, "Couldn't open a socket(...)");

    struct sockaddr_un Address;
    memset(&Address, 0, sizeof(struct sockaddr_un));
    Address.sun_family = AF_UNIX;
    strncpy(Address.sun_path, "/tmp/.X11-unix/X0", sizeof(Address.sun_path)-1);

    int Status = connect(Socket, (struct sockaddr *)&Address, sizeof(Address));
    VerifyOrDieWidthErrno(Status == 0, "Couldn't connect to a unix socket with connect(...)");

    int SetupStatus = X_InitiateConnection(Socket);

    if(SetupStatus == 0) {
        int32_t X = 100;
        int32_t Y = 100;
        uint32_t Width = 600;
        uint32_t Height = 300;
        int WindowId = X_CreatWindow(Socket, X, Y, Width, Height);

        X_MapWindow(Socket, WindowId);

        int32_t FontId = GetNextId();
        X_OpenFont(Socket, (int8_t *)"fixed", FontId);

        int32_t GcId = GetNextId();
        X_CreateGC(Socket, GcId, FontId);

        struct pollfd PollDescriptors[1] = {};
        PollDescriptors[0].fd = Socket;
        PollDescriptors[0].events = POLLIN;
        int32_t DescriptorCount = 1;
        int32_t IsProgramRunning = 1;
        while(IsProgramRunning){
            int32_t EventCount = poll(PollDescriptors, DescriptorCount, -1);

            if(PollDescriptors[0].revents & POLLERR) {
                printf("------- Error\n");
            }

            if(PollDescriptors[0].revents & POLLHUP) {
                printf("---- Connection close\n");
                IsProgramRunning = 0;
            }

            char* t1 = "Hello, World!";
            char* t2 = "This is a test text directly written to X";
            char* t3 = "Whooha. Is this even legal? Let's keep a secret!";
            WriteText(Socket, WindowId, GcId, GlobalTextOffsetX, GlobalTextOffsetY, t1, strlen(t1));
            WriteText(Socket, WindowId, GcId, GlobalTextOffsetX, GlobalTextOffsetY + 15, t2, strlen(t2));
            WriteText(Socket, WindowId, GcId, GlobalTextOffsetX, GlobalTextOffsetY + 30, t3, strlen(t3));

            GetAndProcessReply(PollDescriptors[0].fd);
        }
    }

}

Fordítás:

gcc main.c -o main

Ennyi! A linkelt blogposztban részletesen el van magyarázva minden, érdemes elolvasni hozzá.

3D modellező egy hét alatt

Fórumok

Nem semmi a csóka, 1 hét alatt összedobott egy komplett 3D modellező programot. Mivel C-ben írta, így gond nélkül wasm-ra is fordítható, és böngészőben is fut. Mindezt szépen le is dokumentálta, tecső videóval, bloggal stb.
Külön érdekesség, hogy a videóban azt is elmondja, miért választotta a Signed Distance Field-et a mesh helyett, és remek animációkkal még a működési elvét is elmagyarázza, roppant tanulságos!

ví dejó: https://youtu.be/-Xb3Kk3HhIw (akkor is érdemes megnézni, ha nem érdekel a megvalósítás)
webdemó: https://danielchasehooper.com/projects/shapeup/ (interaktív, kipróbálható)
forrás: https://github.com/danielchasehooper/ShapeUp-public
blog: https://danielchasehooper.com/posts/shapeup/ (itt belemegy az implementációs részletekbe is)

A blogon egyébként arra is kitér, hogy miért a C-t választotta. SPOILER: pont azokat az érveket hozza fel, amiket már én is jó ideje hangoztatok, pedig nem valószínű. hogy ez a Daniel gyerek sokat olvasná a HUP-ot :-D

És mindezt tokkal vonóval 1 hét alatt! (Ebben benne van a videó elkészítése is, ami állítólag tovább tartott, mint a programot megírni)

STM32 arm debuggolás

Fórumok

Bare metal szintről próbálok beletanulni az ST arm alapú processzorainak debuggolásának. A fejlesztő rendszer egy Debian 12 gépen fut.
Az első a tool chain és aztán a jó öreg "blinky" és miután ez működik jöhet a debugger.. Miután fe
Több bare metal ismertetőt átolvastam mindegyik arra fut ki, hogy addjam ki a parancsot:

$ arm-none-eabi-gdb main.elf

Úgy tűnik ez elavult, a tool chain megvan, azonban a gdb ügyében a Debian elküld, hogy telepítsem fel az arm architecturát. Csináltam már ilyesmit, de konkrétan a debuggolás viszonylatában nem :(
Nem találok hozzá leírást.

Ha feltelpítem az arm architecturát hogy indíthatok egy debug sessiont?

STM32F051 CMSIS bare metal header files

Fórumok

Bare metal programming -hoz keresem a megfelelő CMSIS fájlokat, arm-none-eabi tool chain, de eltévedtem az erdőben.

STM32F051 -es MCU-hoz keresem a megfelelő CMSIS fájlokat. Az egyik git repoban találtam olyat, hogy stm32f031x6.h (ezzel sikerült is egy kínai gyártmányú kis panelt a blink-ig felébreszteni).
A google a developper.arm.com -ot dobja fel, de az mintha a keil-hez fűződne ill. valami olyan ide-hez ami kezeli a (számomra szokatlan) .pack fájlt.
Megint a google feldob egy kimondottan az STMicroelectronics "cmsis_core" repót a git-en. Viszont itt nyoma nincs az ilyen nevesített fájloknak amit idéztem, olyat látok benne mint az stm32f0xx.h -t (amit az előzőleg idézett blinky repo is használ).

Két, jónak mondható bare metal programming guide-t is találtam, az egyik a git "cpq" nevével illetve a másik "független" a Vivonomicon sorozata.
Először a cpq verzióval indultam el (persze ott sincs pont az F051 mcu) de még nem sikerült működésre bírni vele a kártyámat.
Találtam egy igen régi csomagot is egy bizonyos "Frank Duignan" blogja - több stm gyártmányú arm-al is foglalkozik, viszont igen régi, és persze nincs ott sem szó az F051-ről.

Hogy lehet összerakni, egy használható fejlesztői CMSIS fájl készletet az STM32F051 -hez?

local/label szimbolumok es/vagy szimbolum-mintak kiszedese

Fórumok

Sziaztok!

Valamiert bizonyos architekturakon (pl msp430) szeret a GCC ilyen .L* lokalis szimbolumokat beletenni a text szegmensbe. Pelda: 

$ nm main.elf | sort 
[...]
0000cb34 t transmit_get_iface_by_name
0000cb3e t .L8
0000cb58 t .L6
0000cb5e T testled_init
[...]

amik szepen megjelennek az objdump + disassembly kimenetben is:

0000cb34 <transmit_get_iface_by_name>:
    cb34:       2a 15           pushm   #3,     r10     ;16-bit words
    cb36:       08 4c           mov     r12,    r8      ;
    cb38:       39 40 5c 20     mov     #8284,  r9      ;#0x205c
    cb3c:       4a 43           clr.b   r10             ;

0000cb3e <.L8>:
    cb3e:       0d 48           mov     r8,     r13     ;
    cb40:       2c 49           mov     @r9,    r12     ;
    cb42:       b0 12 72 f0     call    #-3982          ;#0xf072
    cb46:       0c 93           cmp     #0,     r12     ;r3 As==00
    cb48:       07 24           jz      $+16            ;abs 0xcb58
    cb4a:       1a 53           inc     r10             ;
    cb4c:       39 50 36 00     add     #54,    r9      ;#0x0036
    cb50:       3a 90 06 00     cmp     #6,     r10     ;
    cb54:       f4 23           jnz     $-22            ;abs 0xcb3e
    cb56:       3a 43           mov     #-1,    r10     ;r3 As==11
 
0000cb58 <.L6>:
    cb58:       0c 4a           mov     r10,    r12     ;
    cb5a:       28 17           popm    #3,     r10     ;16-bit words
    cb5c:       30 41           ret
 
0000cb5e <testled_init>:
    cb5e:       d2 d3 04 02     bis.b   #1,     &0x0204 ;r3 As==01
    cb62:       30 41           ret

Ha meg itten ezeket fel is oldana az ugyan legalabb valamit segithet az ertelmezesben (lasd: 0xcb54-es cimen  az a `jnz $-22` ehelyett mondjuk `jnz .L8` is lehetne), de mivel meg az sem, ezert ez ugy erosen ront a kimenetek (nm, objdump) olvashatosagan mar egy kozepes projektnel is... :( Peldaul itten most ennel a projektnel:

$ nm main.elf | grep " T " | wc -l
103
$ nm main.elf | grep ".L" | wc -l
645

azaz minden valodi text szimbolumra jut valamivel tobb mint 6 ilyen label-szeruseg... aztan talaljunk meg valamit itten a szenakazalban...  Szoval az X problema az hogy hogyan lehetne azt elerni hogy ezek mar bele se keruljenek a *.o/*.elf-be, az Y problema pedig hogy hamar belekerultek, hogyan lehet kiszedni es/vagy megszabadulni? Az objcopy peldaul tud section pattern-ekre szurni (lasd: `objcopy -j '*' -j '!.persist*' -j ...`), de szimbolum patternre lehet? Tulajdonkeppen semmi nem erdekel ami .L* :] Mas embedded/cross architekturakon (avr, rv32, armv6/v7) nem lattam meg ilyet, de msp430-nal ez most kifejezetten nyugos ha valami szitu van :/

thx, A.

AddressSanitizer:DEADLYSIGNAL végtelen loop

Fórumok

Hátha érdekel valakit, elkerülendő a szívás ....

Ubuntu 22.04.1, gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0. Az Ubuntu egy i5 Macbookon fut Parallels virtualizáció.

curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.17
Release-Date: 2022-01-05

Van két rövid C program(ocska), semmi extra, parancssoros fordítás: gcc -Wall -Werror -pedantic -Wextra -fsanitize=address ... -lcurl -lm, weboldal lekérés és feldolgozás. Fordítás során semmit nem ír ki, nincs hiba, nincs megjegyzés.

A két fájl a fő funkciók tekintetében ugyanaz.

Elindítod az egyik fájlt, minden OK, teszi amit tenni kell, lefut, kilép hiba nélkül.

Elindítod a másodikat, kiírja a konzolra: AddressSanitizer:DEADLYSIGNAL végtelen loop-ban, abba sem akarja hagyni.

 

Megoldás:

sudo sysctl -w vm.mmap_rnd_bits=28

Innen szedtem a megoldást, miután feladtam a kód milliomodik átnézését:

https://stackoverflow.com/questions/77672217/gcc-fsanitize-address-resu…

Egészségetekre!

#define trükk

Fórumok

Sziasztok!

Letre kene hoznom par ilyesmi szimbolumot C preprocessz soran:

#define XYZ_WHAT  XYZ_42WHAT
#define XYZ_EVER  XYZ_42EVER
#define XYZ_LOLZ  XYZ_42LOLZ

Ahol a "42" az egy elore adott konstans, amit 1x szeretnek csak definialni az elejen. Ilyesmivel probalkoztam hogy:

#define __xyz_def(a,b)   XYZ_##a##b
#define XYZ_WHAT __xyz_def(42,WHAT)
#define XYZ_EVER __xyz_def(42,EVER)
/* ... */

Ez itten fentebb mar ugye egy fokkal - jobb de a preprocessz alatt nem tudom beleirni azt hogy:

#define NUM  42
#define __xyz_def(a,b)   XYZ_##a##b
#define XYZ_WHAT __xyz_def(NUM,WHAT)
/* ... */

Mi is volt erre a trukk? :) Vagy legalabbis ugy remlik hogy volt erre valami, de sehol sem lelem... 

Thx, A.

gcc: __attribute__ (( ... )) minden fuggvenyre?

Fórumok

Sziasztok!

Lehet hogy tul trivialis a kerdes, de azt hogyan tudom elerni mondjuk leginkabb `gcc` forditasi parameterekkel hogy egy adott *.c => *.o forditas soran minden fuggveny egy bizonyos __attribute_--t (azon belul is most konkretan __attribute__ (( section (".whatever") ))-t) kapjon? Csak a fuggvenyek, szoval a .text(.*) vagy a (.*).text-be meno szimbolumok... Most csak a section-ok szempontjabol erdekes de lehet hogy kesobb mas kapcsan is erdekes lehet.

thx, A.

ld + _start + .text + ordering

Fórumok

Sziasztok!

Szinten RISC-V (32bites, beagyazott) tema: probalok egy sima mezei programot leforditani az xpack-riscv-none-elf toolchain segitsegevel. A forditas kapcsan alapjaraton minden jonak tunik, kiveve az hogy a linkeles utan ezt kapom:

$ nm main.elf  | sort | grep " T "
20000000 T exit
20000026 T main
20000092 T _start
20000116 T main_task
[...]

Ami ugye erosen nem jo, es ezzel egyetertesben a `readelf --file-header main.elf` is ezt mondja:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
[...]
  Entry point address:               0x20000092
[...]

Merthat a processzor (vagyis annak a bootromja) az olyan hogy 0x20000000-rol szeret(ne) indulni. Ami megfurcsabbba teszi a dolgot, hogy a main() es a main_task() ugyanabbol a forras-modulbol jon, szoval meg egy *.o-bol jovo fuggvenyek koze is teszi be a linker a _start szimbolumnak megfelelo valamit. Ezutobbi papiron lehetne a forditas + linkeles soran kiadott `-ffunction-sections` + `-Wl,--gc-sections` eredmenye is (akar), de ha ezutobbiakat kikapcsolom akkoris ugyanez a helyzet :/ Akkor is ide (egyebkent pont a 0x...92-es cimre) kerul a _start. 

Ez az xPack az a newlib-et hasznalja. Eddig csak picolibc-t hasznaltam RISC-V-s projektekre, szoval lehet hogy ez a newlib kinja ugy altalaban (es pl ARMv6-M vagy ARMv7-M eseten is "ilyen"). 

Mit lehetne itten tenni? Hogyan tudnam eroltetni az linkert (pl a megfelelo -Wl,... kapcsoloval) hogy marpedig a _start az legyen a 0x20000000 cimen es/vagy a .text legelejen? Fuggetlenul attol hogy a .text melyik subsection-jeben mi van? (( Mondjuk ettol fuggetlenul ha atirom a bootrom-ban hogy a 0x20000092-es cimrol induljon a program, akkor sem indul - meg - el, szoval vsz lesz itt mas turpissag is, de ez mas kerdes... ))

Maga a szerkesztes egyebkent olyan hogy a text is a RAM-ba (a 0x20000000-s cimre) van eroltetve, szoval a beagyazott rendszer jelleg ellenere ez most egy teljesen "von Neumann" linkeles: azaz mind a text, mind a data meg a bss (meg a heap) az a 0x20000000 cimtartomanyban van (alul a text, felul a tobbi). Es ez a "von Neumann" linkeles szepen mukodik picolibc eseten, szoval ezzel nem kene hogy gond legyen. Csak a newlib-nek nem tetszik.

thx, A.