GCC - wlshiu/my_note GitHub Wiki
-
structure alignment
#pragma pack(1) typedef struct sSampleStruct { char Data1; int Data2; unsigned short Data3; char Data4; }__attribute__((packed)) sSampleStruct_t; #pragma pack()
-
flexible array member
struct test { int a; // It MUST exist a member in this structure. char c[]; // flexible array, it MUST put at the last member. // Some compiler support 'char c[0]' }; struct test *p = (struct test*)malloc(sizeof(struct test) + 100*sizeof(char));
- It not occupies the size when sizeof().
- It must be the last member of a structure.
-
function point
int foo(int a, int b) { return a + b; } int main() { int (*fp_func)(int, int); fp_func = foo; fp_func(3, 5); }
-
macro return
#include <stdio.h> #define DBG(s, b...) \ { \ printf(__FILE__ "@%d, %s(): " s, __LINE__, __FUNCTION__, ##b); \ fflush(stdout); \ } #define round_down(f) \ ({ \ int __ret = 0; \ __ret = (int)f; \ __ret; \ }) int main(int argc, char *argv[]) { DBG("This is a debug message\n"); printf("round_down(%f) = %d\n", 4.5, round_down(4.5)); printf("round_down(%f) = %d\n", 9.5, round_down(9.5)); return 0; }
-
static assert
#define __STRCAT(a, b) a##b #define __XSTRCAT(a, b) __STRCAT(a, b) #define __static_assert(const_expr, _mess) enum { __XSTRCAT(_verify_static_, __LINE__) = 1/(!!(const_expr)) }
// example typedef struct __attribute__ ((packed)) { uint8_t bLength; uint8_t bDescriptorType; uint8_t bEndpointAddress; struct __attribute__ ((packed)) { uint8_t xfer : 2; uint8_t sync : 2; uint8_t usage : 2; uint8_t : 2; } bmAttributes; uint16_t wMaxPacketSize; uint8_t bInterval; } tusb_desc_endpoint_t; __static_assert( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct");
-
_write v.s _write_r
_write_r
is the Reentrant version of_write
-
_sbrk
改變堆的配置(對 malloc而言) -
_open
開啟檔案(基於控點的) -
_close
關閉檔案 -
_write
寫檔案 -
_read
讀檔案 -
_lseek
重新定向檔案中的位置 -
_fcntl
執行一個檔案說明符的作業 -
_fstat
得到檔案狀態的控點 -
_stat
按名稱得到檔案狀態 -
_link
生成一個檔案鏈結(檔案命名) -
_unlink
移除目錄項 -
_times
讀取時間資訊 -
_gettimeofday
得到時間日期 -
_execve
執行一個檔案 -
_kill
殺死一個程式 -
_getpid
得到程式識別 -
_fork
建立一個新的程式 -
_wait
等待子程式的終止
查看 man GCC 的 -dletters 或 -dCHARS 可以得知更多用法
-
查看目前 GCC 內, 所有定義的 macro
$ gcc -E -dM - < /dev/null
-
GCC 展開巨集 (macro)
$ gcc -E macro.c -o macroDebug_Expand.c
-
保留 define 內容
gcc -E -dM
可以保留 define 內容, 方便查詢原始名稱- 反查 error no
# 查詢 errorno: 111 $ echo "#include <errno.h>" | gcc -E -dM - | grep " 111$" #define ECONNREFUSED 111
- 反查 error no
-
列出 include header files
若希望過濾掉系統標頭檔, 可以改用
-MM
$ echo "#include <stdio.h>" | gcc -E -M - -: /usr/include/stdc-predef.h /usr/include/stdio.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \ /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
-
查看
#define
從那裡 include 的$ gcc -E -dD ./src/XSync.c | egrep "(GetReq|include)" # 418 "/usr/include/X11/Xlibint.h" 3 4 extern void *_XGetRequest(Display *dpy, CARD8 type, size_t len); #define GetReqSized(name,sz,req) req = (x ##name ##Req *) _XGetRequest(dpy, X_ ##name, sz) # 435 "/usr/include/X11/Xlibint.h" 3 4 #define GetReq(name,req) GetReqSized(name, SIZEOF(x ##name ##Req), req)
-
Example 找出
GetReq()
的 source code-
先查在目前
XSync.c
中,GetReq()
是由那個 header 引入的$ gcc -E ./src/XSync.c | grep GetReq extern void *_XGetRequest(Display *dpy, CARD8 type, size_t len); = (xSyncInitializeReq *) _XGetRequest(dpy, 0, 8)
-
前項結果沒看到宣告, 猜測
GetReq()
可能是 macro API, 改成從#define
查$ gcc -E -dM ./src/XSync.c | grep GetReq #define GetReqSized(name,sz,req) req = (x ##name ##Req *) _XGetRequest(dpy, X_ ##name, sz) #define GetReq(name,req) GetReqSized(name, SIZEOF(x ##name ##Req), req)
得知
GetReq()
其實是_XGetRequest()
-
查看
_XGetRequest()
從那裡引入的gcc -E ./src/XSync.c | less ... # 418 "/usr/include/X11/Xlibint.h" 3 4 extern void *_XGetRequest(Display *dpy, CARD8 type, size_t len); ...
-
接著查
/usr/include/X11/Xlibint.h
在個套件# 查詢已安裝套件, 速度較快 $ dpkg --search /usr/include/X11/Xlibint.h libx11-dev:amd64: /usr/include/X11/Xlibint.h # 查詢全部套件 $ apt-file search /usr/include/X11/Xlibint.h libx11-dev: /usr/include/X11/Xlibint.h
-
取得
libx11
然後找到 source code 的位置$ apt-get source libx11-dev ... $ grep -RI _XGetRequest . ./src/XlibInt.c:void *_XGetRequest(Display *dpy, CARD8 type, size_t len)
-
-
__SSAT
#if defined (__GNUC__) static inline int __SSAT_GUN(int32_t VAL, int32_t BITPOS) { int32_t min = -(1<<(BITPOS-1)); int32_t max = (1<<(BITPOS-1)) - 1; if (VAL < min) return min; else if (VAL > max) return max; else return VAL; } #define __SSAT(VAL, BITPOS) __SSAT_GUN(VAL,BITPOS) #else #define __SSAT(VAL, BITPOS) _ssatl(VAL , 0, BITPOS) #endif #if defined(__GNUC__) #define __CLZ __builtin_clz #else #define __CLZ __clz #endif
-
get PC register
#define __GET_PC(pAddr) __asm volatile ("MOV %0, PC\n" : "=r" (*pAddr))
{
uint32_t addr = 0;
__GET_PC(&addr);
printf("@ %x\n", addr);
}
-
__libc_init_array()
void __libc_init_array (void) { size_t count; size_t i; count = __preinit_array_end - __preinit_array_start; for (i = 0; i < count; i++) __preinit_array_start[i](); _init(); count = __init_array_end - __init_array_start; for (i = 0; i < count; i++) __init_array_start[i](); }
/* link script */ SECTIONS { ... .preinit_array : { . = ALIGN(8); PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array *)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(8); } > FLASH .init_array : { . = ALIGN(8); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array *)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(8); } > FLASH .fini_array : { . = ALIGN(8); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array *)) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(8); } > FLASH ... }
-
section
int foo_var __attribute__((section(".xdata"))) = 0; // no declare, directly put attribute at function __attribute__((section(".xinit"))) int foo_func(void) { return 1111; } int foo_func2(void) __attribute__((section(".xinit"))); // put attribute at declare int foo_func2(void) { return 2222; }
-
constructor/destructor
- 在執行 main()前, 先 call 有 attribute((constructor))修飾的 function
- 在結束 main()後, 再 call 有 attribute((destructor))修飾的 function
static __attribute__((constructor)) void before() { printf("before...\n"); } static __attribute__((destructor)) void after() { printf("after...\n"); }
- constructor(PRIORITY)/destructor(PRIORITY)
In constructor, PRIORITY小的先執行. In destructor, PRIORITY大的先執行
constructor 和 destructor 的 PRIORITY順序相反
-
replace function
-
__attribute__ (alias)
/* 所有調用到 malloc() 的地方都將調用 my_malloc(), 即使是 gcc 內建的 malloc() 也不再可用 */ void *malloc(size_t) __attribute__((alias("my_malloc"))); void *my_malloc(size_t size) { printf("Try to malloc %ld bytes\n", size); return __libc_malloc(size); }
-
-Wl,--wrap=[symbol]
任何對symbol未定義的引用(undefined reference)會被解析成__wrap_symbol, 而任何對
__real_symbol
未定義的引用會被解析成symbol. 即當一個名為 symbol 符號使用 wrap 功能時, 工程中任何用到 symbol 符號的地方實際使用的是__wrap_symbol
符號, 任何用到__real_symbol
的地方實際使用的是真正的 symbol# linker 會將 malloc() 替換為 __wrap_malloc() LDFLAGS += -Wl,--wrap=malloc
extern void *__real_malloc(size_t size); // 連結到真正的 libc malloc() function void *__wrap_malloc(size_t size) { fprintf(stdout, "===> malloc %d\n", size); return __real_malloc(size); } int main(void) { char *pbuf = 0; pbuf = malloc(10); if( pbuf ) free(pbuf); return 0; }
-
-
condition
(so_size > size) ? (stream[0].size = so_size) : (stream[0].size = size);
-
vmlinux.lds
arch/arm/kernel/compressed/vmlinux.lds是由arch/arm/kernel/compressed/vmlinux.lds.S生成的
- 生成規則
# path: scripts/Makefile.build # Linker scripts preprocessor (.lds.S -> .lds) # --------------------------------------------------------------------------- quiet_cmd_cpp_lds_S = LDS $@ cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \ -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< $(obj)/%.lds: $(src)/%.lds.S FORCE $(call if_changed_dep,cpp_lds_S)
- 擴展命令
$ arm-none-eabi-gcc -E -Wp,-MD,arch/arm/boot/compressed/.vmlinux.lds.d -nostdinc -isystem /home/liminghao/bin/bin/arm-none-eabi-4.7.3/bin/../lib/gcc/arm-none-eabi/4.7.3/include -I./arch/arm/include -Iarch/arm/include/generated/uapi -Iarch/arm/include/generated -Iinclude -I./arch/arm/include/uapi -Iarch/arm/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -DTEXT_START="0" -DBSS_START="ALIGN(8)" -mlittle-endian -P -C -Uarm -D__ASSEMBLY__ -DLINKER_SCRIPT -o arch/arm/boot/compressed/vmlinux.lds arch/arm/boot/compressed/vmlinux.lds.S 生成命令中的參數-E,它並不編譯,而只是進行預處理。它的格式與源文件格式是一致的。
$ arm-linux-gcc -E -Wp,-MD,arch/arm/kernel/.vmlinux.lds.d -nostdinc ...... -D__KERNEL__ -mlittle-endian ...... -DTEXT_OFFSET=0x00008000 -P -C -Uarm -D__ASSEMBLY__ -o arch/arm/kernel/vmlinux.lds arch/arm/kernel/vmlinux.lds.S
-
get current function
#define GET_CALLER_ADDR() __builtin_return_address(0) // the caller of this function (backtrace frame)
-
只想要把某個library的
.o
放入的話使用
*xxx.a:*yyy.o (.bss*)
.bss_RAM2 : ALIGN(4) { *libmytest.a:*.o (.bss*) *(.bss.$RAM2*) *(.bss.$RamLoc64*) . = ALIGN(4) ; } > RamLoc64
-
不想要把特定檔案的section放入
可以使用
EXCLUDE_FILE
/* 想放除了 foo.o、bar.o 外, 所有的 '.bss section' */ (*(EXCLUDE_FILE (*foo.o *bar.o) .bss))
-
relocation truncated to fit: xxxx
這種情況一般出現在 assembly code 中, 有些跳轉指令的跳轉範圍很小. 而當要跳轉到的地址超出了範圍, 那麼就會報錯. 原則上將替換更大範圍的跳轉指令即可解決.
$ readelf -w ./libmsmart.a | grep DW_AT_producer
當 MSYS2 安裝成功後, 會有三種版本的 Shell 供您使用
如果需要編譯32位元的版本的執行檔, 就使用 MinGW-w64 Win32 Shell
如果需要編譯64位元的版本的執行檔, 就使用 MinGW-w64 Win64 Shell
至於 MSYS2 Shell
和其他兩者又有何差別?
在 MSYS2 Shell
使用 gcc 編譯出來的執行檔會需要依賴 msys-2.0.dll
, 但是 MSYS2 Shell
有非常良好的 POSIX 支援.
一般來說
MSYS2 Shell
通常用於編譯 GNU 相關的 Linux 作業系統工具, 或者需要編譯 POSIX 支援的軟體, 才使用 MSYS2 這個 Shell