* [FFmpeg-devel] [PATCH] Mark C globals with small code model (PR #20150)
@ 2025-08-06 23:19 pranavk
0 siblings, 0 replies; only message in thread
From: pranavk @ 2025-08-06 23:19 UTC (permalink / raw)
To: ffmpeg-devel
PR #20150 opened by pranavk
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20150
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20150.patch
By default, all globals in C/C++ compiled by clang are allocated
in non-large data sections. See [1] for background on code models.
For PIC (Position independent code), this is fine as long as binary is
small but as binary size increases, users maybe want to use medium/large
code models (-mcmodel=medium) which moves data in to large sections.
As data in these large sections cannot be accessed using PIC code
anymore (as it may be too far away), compiler ends up using a different
instruction sequence when building C/C++ code -- using GOT to access
these globals (which can be relaxed by linker at link time if binary
ends up being smaller).
However, hardcoded assembly (external asm files, as well as inline
assembly) continue to access these globals defined in C/C++ files using
older (and invalid) instruction sequence. This patch introduces a new macro
EXTERN_ASM_VAR that we use to declare extern variables, and expand the
definition of this and other related macros (DECLARE_ASM_CONST,
DECLARE_ASM_ALIGNED) to include attribute_mcmodel_small. The new attributes
ensures these variables are still accessible from hardcoded assembly.
This patch should not have any affect on builds that use small code
model, which is the default mode.
[1] https://eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models
From b87ddb67163ec6834b294dc535e019efe1e0a91d Mon Sep 17 00:00:00 2001
From: Pranav Kant <prka@google.com>
Date: Tue, 5 Aug 2025 16:03:54 -0700
Subject: [PATCH] Mark C globals with small code model
By default, all globals in C/C++ compiled by clang are allocated
in non-large data sections. See [1] for background on code models.
For PIC (Position independent code), this is fine as long as binary is
small but as binary size increases, users maybe want to use medium/large
code models (-mcmodel=medium) which moves data in to large sections.
As data in these large sections cannot be accessed using PIC code
anymore (as it may be too far away), compiler ends up using a different
instruction sequence when building C/C++ code -- using GOT to access
these globals (which can be relaxed by linker at link time if binary
ends up being smaller).
However, hardcoded assembly (external asm files, as well as inline
assembly) continue to access these globals defined in C/C++ files using
older (and invalid instruction sequence). So, we mark all such globals
with an attribute that forces them to be allocated in small sections
allowing them to validly be accessed from the assembly code.
This patch should not have any affect on builds that use small code
model, which is the default mode.
[1] https://eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models
---
libavcodec/ac3dsp.h | 4 +-
libavcodec/cabac.h | 4 +-
libavcodec/x86/constants.h | 79 +++++++++++++++++----------------
libavutil/attributes.h | 6 +++
libavutil/attributes_internal.h | 16 +++++++
libavutil/mem_internal.h | 16 ++++---
6 files changed, 78 insertions(+), 47 deletions(-)
diff --git a/libavcodec/ac3dsp.h b/libavcodec/ac3dsp.h
index b1b2bced8f..914824025f 100644
--- a/libavcodec/ac3dsp.h
+++ b/libavcodec/ac3dsp.h
@@ -25,11 +25,13 @@
#include <stddef.h>
#include <stdint.h>
+#include "libavutil/mem_internal.h"
+
/**
* Number of mantissa bits written for each bap value.
* bap values with fractional bits are set to 0 and are calculated separately.
*/
-extern const uint16_t ff_ac3_bap_bits[16];
+EXTERN_ASM_VAR(const uint16_t, ff_ac3_bap_bits)[16];
typedef struct AC3DSPContext {
/**
diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h
index 38d06b2842..70730e4059 100644
--- a/libavcodec/cabac.h
+++ b/libavcodec/cabac.h
@@ -29,7 +29,9 @@
#include <stdint.h>
-extern const uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
+#include "libavutil/mem_internal.h"
+
+EXTERN_ASM_VAR(const uint8_t, ff_h264_cabac_tables)[512 + 4*2*64 + 4*64 + 63];
#define H264_NORM_SHIFT_OFFSET 0
#define H264_LPS_RANGE_OFFSET 512
#define H264_MLPS_STATE_OFFSET 1024
diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h
index 4a55adb5b3..c2e0fd8f02 100644
--- a/libavcodec/x86/constants.h
+++ b/libavcodec/x86/constants.h
@@ -23,49 +23,50 @@
#include <stdint.h>
+#include "libavutil/mem_internal.h"
#include "libavutil/x86/asm.h"
-extern const ymm_reg ff_pw_1;
-extern const ymm_reg ff_pw_2;
-extern const xmm_reg ff_pw_3;
-extern const ymm_reg ff_pw_4;
-extern const xmm_reg ff_pw_5;
-extern const xmm_reg ff_pw_8;
-extern const xmm_reg ff_pw_9;
-extern const uint64_t ff_pw_15;
-extern const xmm_reg ff_pw_16;
-extern const xmm_reg ff_pw_18;
-extern const xmm_reg ff_pw_20;
-extern const xmm_reg ff_pw_32;
-extern const uint64_t ff_pw_53;
-extern const xmm_reg ff_pw_64;
-extern const uint64_t ff_pw_128;
-extern const ymm_reg ff_pw_255;
-extern const ymm_reg ff_pw_256;
-extern const ymm_reg ff_pw_512;
-extern const ymm_reg ff_pw_1023;
-extern const ymm_reg ff_pw_1024;
-extern const ymm_reg ff_pw_2048;
-extern const ymm_reg ff_pw_4095;
-extern const ymm_reg ff_pw_4096;
-extern const ymm_reg ff_pw_8192;
-extern const ymm_reg ff_pw_m1;
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_1);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_2);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_3);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_4);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_5);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_8);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_9);
+EXTERN_ASM_VAR(const uint64_t, ff_pw_15);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_16);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_18);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_20);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_32);
+EXTERN_ASM_VAR(const uint64_t, ff_pw_53);
+EXTERN_ASM_VAR(const xmm_reg, ff_pw_64);
+EXTERN_ASM_VAR(const uint64_t, ff_pw_128);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_255);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_256);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_512);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_1023);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_1024);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_2048);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_4095);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_4096);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_8192);
+EXTERN_ASM_VAR(const ymm_reg, ff_pw_m1);
-extern const ymm_reg ff_pb_0;
-extern const ymm_reg ff_pb_1;
-extern const ymm_reg ff_pb_2;
-extern const ymm_reg ff_pb_3;
-extern const ymm_reg ff_pb_80;
-extern const ymm_reg ff_pb_FE;
-extern const uint64_t ff_pb_FC;
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_0);
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_1);
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_2);
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_3);
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_80);
+EXTERN_ASM_VAR(const ymm_reg, ff_pb_FE);
+EXTERN_ASM_VAR(const uint64_t, ff_pb_FC);
-extern const xmm_reg ff_ps_neg;
+EXTERN_ASM_VAR(const xmm_reg, ff_ps_neg);
-extern const ymm_reg ff_pd_1;
-extern const ymm_reg ff_pd_16;
-extern const ymm_reg ff_pd_32;
-extern const ymm_reg ff_pd_64;
-extern const ymm_reg ff_pd_8192;
-extern const ymm_reg ff_pd_65535;
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_1);
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_16);
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_32);
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_64);
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_8192);
+EXTERN_ASM_VAR(const ymm_reg, ff_pd_65535);
#endif /* AVCODEC_X86_CONSTANTS_H */
diff --git a/libavutil/attributes.h b/libavutil/attributes.h
index d15ede1286..a1ac93916d 100644
--- a/libavutil/attributes.h
+++ b/libavutil/attributes.h
@@ -40,6 +40,12 @@
# define AV_HAS_BUILTIN(x) 0
#endif
+#ifdef __has_attribute
+# define AV_HAS_ATTRIBUTE(x) __has_attribute(x)
+#else
+# define AV_HAS_ATTRIBUTE(x) 0
+#endif
+
#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
# define av_always_inline __attribute__((always_inline)) inline
diff --git a/libavutil/attributes_internal.h b/libavutil/attributes_internal.h
index bc85ce77ff..c557fa0af0 100644
--- a/libavutil/attributes_internal.h
+++ b/libavutil/attributes_internal.h
@@ -19,6 +19,7 @@
#ifndef AVUTIL_ATTRIBUTES_INTERNAL_H
#define AVUTIL_ATTRIBUTES_INTERNAL_H
+#include "config.h"
#include "attributes.h"
#if (AV_GCC_VERSION_AT_LEAST(4,0) || defined(__clang__)) && (defined(__ELF__) || defined(__MACH__))
@@ -33,4 +34,19 @@
#define EXTERN extern attribute_visibility_hidden
+/**
+ * Some globals defined in C files are used from hardcoded asm that assumes small
+ * code model (that is, accessing these globals without GOT). This is a problem
+ * when FFMpeg is built with medium code model (-mcmodel=medium) which allocates
+ * all globals in a data section that's unreachable with PC relative instructions
+ * (small code model instruction sequence). We mark all such globals with this
+ * attribute_mcmodel_small to ensure assembly accessible globals continue to be
+ * allocated in sections reachable from PC relative instructions.
+ */
+#if ARCH_X86_64 && defined(__ELF__) && AV_HAS_ATTRIBUTE(model)
+# define attribute_mcmodel_small __attribute__((model("small")))
+#else
+# define attribute_mcmodel_small
+#endif
+
#endif /* AVUTIL_ATTRIBUTES_INTERNAL_H */
diff --git a/libavutil/mem_internal.h b/libavutil/mem_internal.h
index 78adc4f407..0081af0702 100644
--- a/libavutil/mem_internal.h
+++ b/libavutil/mem_internal.h
@@ -29,6 +29,7 @@
#endif
#include "attributes.h"
+#include "attributes_internal.h"
#include "macros.h"
/**
@@ -78,16 +79,19 @@
#if defined(__DJGPP__)
#define DECLARE_ALIGNED_T(n,t,v) alignas(FFMIN(n, 16)) t v
- #define DECLARE_ASM_ALIGNED(n,t,v) alignas(FFMIN(n, 16)) t av_used v
- #define DECLARE_ASM_CONST(n,t,v) alignas(FFMIN(n, 16)) static const t av_used v
+ #define DECLARE_ASM_ALIGNED(n,t,v) alignas(FFMIN(n, 16)) t av_used attribute_mcmodel_small v
+ #define DECLARE_ASM_CONST(n,t,v) alignas(FFMIN(n, 16)) static const t av_used attribute_mcmodel_small v
+ #define EXTERN_ASM_VAR(t,v) extern t attribute_mcmodel_small v
#elif defined(_MSC_VER)
#define DECLARE_ALIGNED_T(n,t,v) __declspec(align(n)) t v
- #define DECLARE_ASM_ALIGNED(n,t,v) __declspec(align(n)) t av_used v
- #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t av_used v
+ #define DECLARE_ASM_ALIGNED(n,t,v) __declspec(align(n)) t attribute_mcmodel_small v
+ #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t attribute_mcmodel_small v
+ #define EXTERN_ASM_VAR(t,v) extern t attribute_mcmodel_small v
#else
#define DECLARE_ALIGNED_T(n,t,v) alignas(n) t v
- #define DECLARE_ASM_ALIGNED(n,t,v) alignas(n) t av_used v
- #define DECLARE_ASM_CONST(n,t,v) alignas(n) static const t av_used v
+ #define DECLARE_ASM_ALIGNED(n,t,v) alignas(n) t av_used attribute_mcmodel_small v
+ #define DECLARE_ASM_CONST(n,t,v) alignas(n) static const t av_used attribute_mcmodel_small v
+ #define EXTERN_ASM_VAR(t,v) extern t attribute_mcmodel_small v
#endif
#if HAVE_SIMD_ALIGN_64
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-08-06 23:19 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-06 23:19 [FFmpeg-devel] [PATCH] Mark C globals with small code model (PR #20150) pranavk
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git